@@ -30,6 +30,8 @@ class CleanDocstore_Batch {
3030 public $ dry_run ;
3131 /** @var bool */
3232 public $ keep_temp ;
33+ /** @var bool */
34+ public $ only_temp ;
3335 /** @var int */
3436 public $ cutoff ;
3537 /** @var DocumentHashMatcher */
@@ -49,10 +51,17 @@ function __construct(Conf $conf, $docstores, $arg) {
4951 $ this ->verbose = isset ($ arg ["verbose " ]);
5052 $ this ->dry_run = isset ($ arg ["dry-run " ]);
5153 $ this ->keep_temp = isset ($ arg ["keep-temp " ]);
54+ $ this ->only_temp = isset ($ arg ["only-temp " ]) || !$ conf ->s3_client ();
5255 $ this ->cutoff = isset ($ arg ["all " ]) ? Conf::$ now + 86400 : Conf::$ now - 86400 ;
5356 $ this ->hash_matcher = new DocumentHashMatcher ($ arg ["match " ] ?? null );
5457 }
5558
59+ /** @param DocumentFileTreeMatch $fm
60+ * @return bool */
61+ static function is_temp ($ fm ) {
62+ return $ fm ->tree ->treeid === 1 ;
63+ }
64+
5665 /** @return ?DocumentFileTreeMatch */
5766 function fparts_random_match () {
5867 $ fmatches = [];
@@ -66,7 +75,7 @@ function fparts_random_match() {
6675 ++$ j ) {
6776 $ fm = $ ftree ->random_match ();
6877 if ($ fm ->is_complete ()
69- && (($ fm-> treeid & 1 ) === 0
78+ && (! self :: is_temp ($ fm)
7079 || max ($ fm ->atime (), $ fm ->mtime ()) < $ this ->cutoff )) {
7180 ++$ n ;
7281 $ fmatches [] = $ fm ;
@@ -75,7 +84,8 @@ function fparts_random_match() {
7584 }
7685 }
7786 if ($ n === 0 ) {
78- $ this ->ftrees [$ i ] = null ;
87+ array_splice ($ this ->ftrees , $ i , 1 );
88+ --$ i ;
7989 }
8090 }
8191 usort ($ fmatches , function ($ a , $ b ) {
@@ -86,11 +96,11 @@ function fparts_random_match() {
8696 return $ at ? -1 : ($ bt ? 1 : 0 );
8797 }
8898 $ aage = Conf::$ now - $ at ;
89- if ($ a -> treeid & 1 ) {
99+ if (self :: is_temp ( $ a ) ) {
90100 $ aage = $ aage > 604800 ? 100000000 : $ aage * 2 ;
91101 }
92102 $ bage = Conf::$ now - $ bt ;
93- if ($ b -> treeid & 1 ) {
103+ if (self :: is_temp ( $ b ) ) {
94104 $ bage = $ bage > 604800 ? 100000000 : $ bage * 2 ;
95105 }
96106 return $ bage <=> $ aage ;
@@ -99,7 +109,7 @@ function fparts_random_match() {
99109 return null ;
100110 } else {
101111 $ fm = $ fmatches [0 ];
102- $ this -> ftrees [ $ fm ->treeid ] ->hide ($ fm );
112+ $ fm ->tree ->hide ($ fm );
103113 return $ fm ;
104114 }
105115 }
@@ -142,7 +152,7 @@ function run() {
142152 }
143153
144154 if (empty ($ this ->docstores ) || !$ this ->conf ->docstore ()) {
145- throw new ErrorException ("No docstore to clean " );
155+ throw new CommandLineException ("No docstore to clean " );
146156 }
147157
148158 preg_match ('/\A((?:\/[^\/%]*(?=\/|\z))+)/ ' , $ this ->docstores [0 ], $ m );
@@ -153,7 +163,7 @@ function run() {
153163 $ ts = disk_total_space ($ usage_directory );
154164 $ fs = disk_free_space ($ usage_directory );
155165 if ($ ts === false || $ fs === false ) {
156- throw new ErrorException ("{$ usage_directory }: Cannot evaluate free space " );
166+ throw new CommandLineException ("{$ usage_directory }: Cannot evaluate free space " );
157167 } else if ($ fs >= $ ts * (1 - ($ this ->max_usage ?? $ this ->min_usage ))) {
158168 if (!$ this ->quiet ) {
159169 fwrite (STDOUT , "{$ usage_directory }: free space sufficient \n" );
@@ -170,13 +180,13 @@ function run() {
170180
171181 foreach ($ this ->docstores as $ i => $ dp ) {
172182 if (!str_starts_with ($ dp , "/ " ) || strpos ($ dp , "% " ) === false ) {
173- throw new ErrorException ("{$ dp }: Bad docstore pattern " );
183+ throw new CommandLineException ("{$ dp }: Bad docstore pattern " );
184+ }
185+ if (!$ this ->only_temp ) {
186+ $ this ->ftrees [] = new DocumentFileTree ($ dp , $ this ->hash_matcher , 0 );
174187 }
175- $ this ->ftrees [] = new DocumentFileTree ($ dp , $ this ->hash_matcher , count ($ this ->ftrees ));
176188 if (!$ this ->keep_temp ) {
177- $ this ->ftrees [] = new DocumentFileTree (Filer::docstore_fixed_prefix ($ dp ) . "tmp/%w " , $ this ->hash_matcher , count ($ this ->ftrees ));
178- } else {
179- $ this ->ftrees [] = null ;
189+ $ this ->ftrees [] = new DocumentFileTree (Filer::docstore_fixed_prefix ($ dp ) . "tmp/%w " , $ this ->hash_matcher , 1 );
180190 }
181191 }
182192
@@ -185,8 +195,7 @@ function run() {
185195 while ($ count > 0
186196 && ($ usage_threshold === null || $ bytesremoved < $ usage_threshold )
187197 && ($ fm = $ this ->fparts_random_match ())) {
188- if (($ fm ->treeid & 1 ) !== 0
189- || $ this ->check_match ($ fm )) {
198+ if (self ::is_temp ($ fm ) || $ this ->check_match ($ fm )) {
190199 $ size = filesize ($ fm ->fname );
191200 if ($ this ->dry_run || unlink ($ fm ->fname )) {
192201 if ($ this ->verbose ) {
@@ -205,30 +214,31 @@ function run() {
205214 if (!$ this ->quiet ) {
206215 fwrite (STDOUT , $ usage_directory . ": " . ($ this ->dry_run ? "would remove " : "removed " ) . plural ($ nsuccess , "file " ) . ", " . plural ($ bytesremoved , "byte " ) . "\n" );
207216 }
208- if ($ nsuccess == 0 ) {
209- fwrite (STDERR , "Nothing to delete \n" );
217+ if ($ nsuccess === 0 && ! $ this -> quiet ) {
218+ fwrite (STDERR , "Nothing to clean \n" );
210219 }
211- return $ nsuccess && $ nsuccess == $ ndone ? 0 : 1 ;
220+ return $ nsuccess > 0 && $ nsuccess = == $ ndone ? 0 : 1 ;
212221 }
213222
214223 /** @return CleanDocstore_Batch */
215224 static function make_args ($ argv ) {
216225 $ arg = (new Getopt )->long (
217226 "name:,n: ! " ,
218227 "config: ! " ,
219- "help,h " ,
220228 "count:,c: {n} =COUNT Clean up to COUNT files " ,
221229 "match:,m: =MATCH Clean files matching MATCH " ,
222- "verbose,V " ,
223230 "dry-run,d Do not remove files " ,
224231 "max-usage:,u: {f} =FRAC Clean until usage is below FRAC " ,
225232 "min-usage:,U: {f} =FRAC Do not clean if usage is below FRAC " ,
226233 "all Clean all files, including files recently modified " ,
227- "quiet,silent,q " ,
228- "keep-temp " ,
229- "docstore "
234+ "quiet,silent,q Be quiet " ,
235+ "keep-temp Keep temporary files " ,
236+ "only-temp Only clean temporary files " ,
237+ "help,h " ,
238+ "verbose,V Be more verbose " ,
239+ "docstore Output docstore patterns and exit "
230240 )->helpopt ("help " )
231- ->description ("Remove files from HotCRP docstore that are on S3.
241+ ->description ("Remove old files from HotCRP docstore
232242Usage: php batch/cleandocstore.php [-c COUNT|-u FRAC] [-V] [-d] [DOCSTORES...] \n" )
233243 ->parse ($ argv );
234244
0 commit comments