@@ -4,23 +4,23 @@ import play.api.mvc.Request
44import services ._
55import models ._
66import com .mongodb .casbah .commons .{Imports , MongoDBObject }
7- import java .text .SimpleDateFormat
87
8+ import java .text .SimpleDateFormat
99import _root_ .util .{License , Parsers , SearchUtils }
1010
1111import scala .collection .mutable .ListBuffer
1212import Transformation .LidoToCidocConvertion
13- import java .util .{ArrayList , Calendar }
14- import java .io ._
1513
14+ import java .util .{ArrayList , Calendar , Date }
15+ import java .io ._
1616import org .apache .commons .io .FileUtils
1717import org .json .JSONObject
1818import play .api .libs .json .{JsValue , Json }
1919import com .mongodb .util .JSON
20+
2021import java .nio .file .{FileSystems , Files }
2122import java .nio .file .attribute .BasicFileAttributes
22- import java .time .LocalDateTime
23-
23+ import java .time .Instant
2424import collection .JavaConverters ._
2525import scala .collection .JavaConversions ._
2626import javax .inject .{Inject , Singleton }
@@ -31,15 +31,16 @@ import scala.util.parsing.json.JSONArray
3131import play .api .libs .json .JsArray
3232import models .File
3333import play .api .libs .json .JsObject
34- import java .util .Date
35-
3634import com .novus .salat .dao .{ModelCompanion , SalatDAO }
3735import MongoContext .context
3836import play .api .Play ._
3937import com .mongodb .casbah .Imports ._
4038import models .FileStatus .FileStatus
4139import org .bson .types .ObjectId
4240
41+ import java .time .temporal .ChronoUnit
42+ import scala .concurrent .duration .FiniteDuration
43+
4344
4445/**
4546 * Use mongo for both metadata and blobs.
@@ -201,48 +202,41 @@ class MongoDBFileService @Inject() (
201202 * This may be expanded to support per-space configuration in the future.
202203 *
203204 * Reads the following parameters from Clowder configuration:
204- * - archiveAutoAfterDaysInactive - timeout after which files are considered
205+ * - archiveAutoAfterInactiveCount - timeout after which files are considered
205206 * to be candidates for archival (see below)
206- * - archiveMinimumStorageSize - files below this size (in Bytes) should not be archived
207+ * - archiveAutoAfterInactiveUnits - time unit that should be used for the timeout (see below)
208+ * - archiveAutoAboveMinimumStorageSize - files below this size (in Bytes) should not be archived
207209 * - clowder.rabbitmq.clowderurl - the Clowder hostname to pass to the archival extractor
208210 * - commKey - the admin key to pass to the archival extractor
209211 *
210212 * Archival candidates are currently defined as follows:
211- * - file must be over `archiveMinimumStorageSize` Bytes in size
212- * - file must be over `archiveAutoAfterDaysInactive` days old
213+ * - file's size must be greater than `archiveAutoAboveMinimumStorageSize` Bytes
214+ * - file's age must be greater than `archiveAutoAfterInactiveCount` * `archiveAutoAfterInactiveUnits`
215+ * (e.g. 10 days old)
213216 * - AND one of the following must be true:
214217 * - file has never been downloaded (0 downloads)
215218 * OR
216- * - file has not been downloaded in the past `archiveAutoAfterDaysInactive` days
219+ * - file has not been downloaded in the past `archiveAutoAfterInactiveCount` `archiveAutoAfterInactiveUnits`
217220 *
218221 *
219222 */
220223 def autoArchiveCandidateFiles () = {
221- val timeout = configuration(play.api.Play .current).getInt( " archiveAutoAfterDaysInactive " )
224+ val timeout : Option [ Long ] = configuration(play.api.Play .current).getLong( " archiveAutoAfterInactiveCount " )
222225 timeout match {
223226 case None => Logger .info(" No archival auto inactivity timeout set - skipping auto archival loop." )
224- case Some (days ) => {
225- if (days == 0 ) {
227+ case Some (inactiveTimeout ) => {
228+ if (inactiveTimeout == 0 ) {
226229 Logger .info(" Archival auto inactivity timeout set to 0 - skipping auto archival loop." )
227230 } else {
228- // DEBUG ONLY: query for files that were uploaded within the past hour
229- val archiveDebug = configuration(play.api.Play .current).getBoolean(" archiveDebug" ).getOrElse(false )
230- val oneHourAgo = LocalDateTime .now.minusHours(1 ).toString + " -00:00"
231-
232- // Query for files that haven't been accessed for at least this many days
233- val daysAgo = LocalDateTime .now.minusDays(days).toString + " -00:00"
234- val notDownloadedWithinTimeout = if (archiveDebug) {
235- (" stats.last_downloaded" $gte Parsers .fromISO8601(oneHourAgo)) ++ (" status" $eq FileStatus .PROCESSED .toString)
236- } else {
237- (" stats.last_downloaded" $lt Parsers .fromISO8601(daysAgo)) ++ (" status" $eq FileStatus .PROCESSED .toString)
238- }
231+ val unit = configuration(play.api.Play .current).getString(" archiveAutoAfterInactiveUnits" ).getOrElse(" days" )
232+ val timeoutAgo = FiniteDuration (inactiveTimeout, unit)
233+
234+ // Query for files that haven't been accessed for at least this many units
235+ val since = Instant .now().minus(timeoutAgo.length.toLong, ChronoUnit .valueOf(timeoutAgo.unit.toString)).toString + " -00:00"
236+ val notDownloadedWithinTimeout = (" stats.last_downloaded" $lt Parsers .fromISO8601(since)) ++ (" status" $eq FileStatus .PROCESSED .toString)
239237
240238 // Include files that have never been downloaded, but make sure they are old enough
241- val neverDownloaded = if (archiveDebug) {
242- (" stats.downloads" $eq 0 ) ++ (" uploadDate" $gte Parsers .fromISO8601(oneHourAgo)) ++ (" status" $eq FileStatus .PROCESSED .toString)
243- } else {
244- (" stats.downloads" $eq 0 ) ++ (" uploadDate" $lt Parsers .fromISO8601(daysAgo)) ++ (" status" $eq FileStatus .PROCESSED .toString)
245- }
239+ val neverDownloaded = (" stats.downloads" $eq 0 ) ++ (" uploadDate" $lt Parsers .fromISO8601(since)) ++ (" status" $eq FileStatus .PROCESSED .toString)
246240
247241 // TODO: How to get host / apiKey / admin internally without a request?
248242 val host = configuration(play.api.Play .current).getString(" clowder.rabbitmq.clowderurl" ).getOrElse(" http://localhost:9000" )
@@ -257,7 +251,7 @@ class MongoDBFileService @Inject() (
257251 Logger .info(" Archival candidates found: " + matchingFiles.length)
258252
259253 // Exclude candidates that do not exceed our minimum file size threshold
260- val minSize = configuration(play.api.Play .current).getLong(" archiveMinimumStorageSize " ).getOrElse(1000000L )
254+ val minSize = configuration(play.api.Play .current).getLong(" archiveAutoAboveMinimumStorageSize " ).getOrElse(1000000L )
261255
262256 // Loop all candidate files and submit each one for archival
263257 for (file <- matchingFiles) {
0 commit comments