]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - maintenance/cleanupUploadStash.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / maintenance / cleanupUploadStash.php
1 <?php
2 /**
3  * Remove old or broken uploads from temporary uploaded file storage,
4  * clean up associated database records
5  *
6  * Copyright © 2011, Wikimedia Foundation
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  * http://www.gnu.org/copyleft/gpl.html
22  *
23  * @file
24  * @author Ian Baker <ibaker@wikimedia.org>
25  * @ingroup Maintenance
26  */
27
28 require_once __DIR__ . '/Maintenance.php';
29
30 /**
31  * Maintenance script to remove old or broken uploads from temporary uploaded
32  * file storage and clean up associated database records.
33  *
34  * @ingroup Maintenance
35  */
36 class UploadStashCleanup extends Maintenance {
37
38         public function __construct() {
39                 parent::__construct();
40                 $this->addDescription( 'Clean up abandoned files in temporary uploaded file stash' );
41                 $this->setBatchSize( 50 );
42         }
43
44         public function execute() {
45                 global $wgUploadStashMaxAge;
46
47                 $repo = RepoGroup::singleton()->getLocalRepo();
48                 $tempRepo = $repo->getTempRepo();
49
50                 $dbr = $repo->getReplicaDB();
51
52                 // how far back should this look for files to delete?
53                 $cutoff = time() - $wgUploadStashMaxAge;
54
55                 $this->output( "Getting list of files to clean up...\n" );
56                 $res = $dbr->select(
57                         'uploadstash',
58                         'us_key',
59                         'us_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $cutoff ) ),
60                         __METHOD__
61                 );
62
63                 // Delete all registered stash files...
64                 if ( $res->numRows() == 0 ) {
65                         $this->output( "No stashed files to cleanup according to the DB.\n" );
66                 } else {
67                         // finish the read before starting writes.
68                         $keys = [];
69                         foreach ( $res as $row ) {
70                                 array_push( $keys, $row->us_key );
71                         }
72
73                         $this->output( 'Removing ' . count( $keys ) . " file(s)...\n" );
74                         // this could be done some other, more direct/efficient way, but using
75                         // UploadStash's own methods means it's less likely to fall accidentally
76                         // out-of-date someday
77                         $stash = new UploadStash( $repo );
78
79                         $i = 0;
80                         foreach ( $keys as $key ) {
81                                 $i++;
82                                 try {
83                                         $stash->getFile( $key, true );
84                                         $stash->removeFileNoAuth( $key );
85                                 } catch ( UploadStashException $ex ) {
86                                         $type = get_class( $ex );
87                                         $this->output( "Failed removing stashed upload with key: $key ($type)\n" );
88                                 }
89                                 if ( $i % 100 == 0 ) {
90                                         wfWaitForSlaves();
91                                         $this->output( "$i\n" );
92                                 }
93                         }
94                         $this->output( "$i done\n" );
95                 }
96
97                 // Delete all the corresponding thumbnails...
98                 $dir = $tempRepo->getZonePath( 'thumb' );
99                 $iterator = $tempRepo->getBackend()->getFileList( [ 'dir' => $dir, 'adviseStat' => 1 ] );
100                 $this->output( "Deleting old thumbnails...\n" );
101                 $i = 0;
102                 $batch = []; // operation batch
103                 foreach ( $iterator as $file ) {
104                         if ( wfTimestamp( TS_UNIX, $tempRepo->getFileTimestamp( "$dir/$file" ) ) < $cutoff ) {
105                                 $batch[] = [ 'op' => 'delete', 'src' => "$dir/$file" ];
106                                 if ( count( $batch ) >= $this->mBatchSize ) {
107                                         $this->doOperations( $tempRepo, $batch );
108                                         $i += count( $batch );
109                                         $batch = [];
110                                         $this->output( "$i\n" );
111                                 }
112                         }
113                 }
114                 if ( count( $batch ) ) {
115                         $this->doOperations( $tempRepo, $batch );
116                         $i += count( $batch );
117                 }
118                 $this->output( "$i done\n" );
119
120                 // Apparently lots of stash files are not registered in the DB...
121                 $dir = $tempRepo->getZonePath( 'public' );
122                 $iterator = $tempRepo->getBackend()->getFileList( [ 'dir' => $dir, 'adviseStat' => 1 ] );
123                 $this->output( "Deleting orphaned temp files...\n" );
124                 if ( strpos( $dir, '/local-temp' ) === false ) { // sanity check
125                         $this->error( "Temp repo is not using the temp container.", 1 ); // die
126                 }
127                 $i = 0;
128                 $batch = []; // operation batch
129                 foreach ( $iterator as $file ) {
130                         if ( wfTimestamp( TS_UNIX, $tempRepo->getFileTimestamp( "$dir/$file" ) ) < $cutoff ) {
131                                 $batch[] = [ 'op' => 'delete', 'src' => "$dir/$file" ];
132                                 if ( count( $batch ) >= $this->mBatchSize ) {
133                                         $this->doOperations( $tempRepo, $batch );
134                                         $i += count( $batch );
135                                         $batch = [];
136                                         $this->output( "$i\n" );
137                                 }
138                         }
139                 }
140                 if ( count( $batch ) ) {
141                         $this->doOperations( $tempRepo, $batch );
142                         $i += count( $batch );
143                 }
144                 $this->output( "$i done\n" );
145         }
146
147         protected function doOperations( FileRepo $tempRepo, array $ops ) {
148                 $status = $tempRepo->getBackend()->doQuickOperations( $ops );
149                 if ( !$status->isOK() ) {
150                         $this->error( print_r( $status->getErrorsArray(), true ) );
151                 }
152         }
153 }
154
155 $maintClass = "UploadStashCleanup";
156 require_once RUN_MAINTENANCE_IF_MAIN;