|
eZ Publish
[4.0]
|
00001 <?php 00002 // 00003 // Definition of eZDBGarbageCollector class 00004 // 00005 // Created on: <09-Jun-2005 08:42:13 amos> 00006 // 00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00008 // SOFTWARE NAME: eZ Publish 00009 // SOFTWARE RELEASE: 4.0.x 00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS 00011 // SOFTWARE LICENSE: GNU General Public License v2.0 00012 // NOTICE: > 00013 // This program is free software; you can redistribute it and/or 00014 // modify it under the terms of version 2.0 of the GNU General 00015 // Public License as published by the Free Software Foundation. 00016 // 00017 // This program is distributed in the hope that it will be useful, 00018 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 // GNU General Public License for more details. 00021 // 00022 // You should have received a copy of version 2.0 of the GNU General 00023 // Public License along with this program; if not, write to the Free 00024 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00025 // MA 02110-1301, USA. 00026 // 00027 // 00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00029 // 00030 00031 /*! \file ezdbgarbagecollector.php 00032 */ 00033 00034 /*! 00035 \class eZDBGrbageCollector ezdbgarbagecollector.php 00036 \brief Handles garbage collection in the database. 00037 00038 Cleans up garbage (leaks) in the database which can be left behind by 00039 bugs or crashes in the system. 00040 00041 Garbage collection is divided into several static functions which performs 00042 cleanup of one or more tables. What is common for all functions are the 00043 \a $maxTime and \a $sleepTime parameters which controls how long a GC 00044 operation can go on and how long it should sleep between batch operations. 00045 00046 \code 00047 eZDBGarbageCollector::collectBaskets(); 00048 // or 00049 // Perform GC for 5 minutes with 2 second sleep intervals 00050 eZDBGarbageCollector::collectBaskets( 5*60, 2 ); 00051 \endcode 00052 00053 */ 00054 00055 //include_once( 'kernel/classes/ezpersistentobject.php' ); 00056 00057 class eZDBGarbageCollector 00058 { 00059 /*! 00060 Controls the default value for how many items are cleaned in one batch operation. 00061 */ 00062 const ITEM_LIMIT = 3000; 00063 00064 /*! 00065 \static 00066 Removes all baskets which are missing a session entry. 00067 This usually means the basket was not cleaned up when the session was removed. 00068 00069 \param $maxTime The maximum number of seconds the collector should run. 00070 If set to \c false or \c true it will continue until all garbage is collected, 00071 \c false means to try the fastest way possible (may use lots of resources). 00072 \param $sleepTime Controls how many seconds it will sleep between each batch of cleanup, 00073 setting it to \c false means that it should never sleep. 00074 \param $limit Controls how many items are cleaned in one batch operation, 00075 a value of \c false means to use default value. 00076 00077 \note The function will most likely use a little more time than \a $maxTime so 00078 don't depend on it to be accurate. 00079 00080 \note This will also remove the product collection the basket is using. 00081 00082 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00083 the calls within a db transaction; thus within db->begin and db->commit. 00084 */ 00085 function collectBaskets( $maxTime = false, $sleepTime = false, $limit = false ) 00086 { 00087 $db = eZDB::instance(); 00088 00089 if ( $maxTime === false and $db->hasRequiredServerVersion( '4.0', 'mysql' ) ) 00090 { 00091 $sql = "DELETE FROM ezbasket, ezproductcollection, ezproductcollection_item, ezproductcollection_item_opt 00092 USING ezsession 00093 RIGHT JOIN ezbasket 00094 ON ezsession.session_key = ezbasket.session_id 00095 LEFT JOIN ezproductcollection 00096 ON ezbasket.productcollection_id = ezproductcollection.id 00097 LEFT JOIN ezproductcollection_item 00098 ON ezproductcollection.id = ezproductcollection_item.productcollection_id 00099 LEFT JOIN ezproductcollection_item_opt 00100 ON ezproductcollection_item.id = ezproductcollection_item_opt.item_id 00101 WHERE ezsession.session_key IS NULL"; 00102 $db->query( $sql ); 00103 return; 00104 } 00105 00106 // Find all baskets which are lacking a session (db leaks) 00107 if ( $db->hasRequiredServerVersion( '8', 'oracle' ) ) 00108 { 00109 $sql = "SELECT id, productcollection_id 00110 FROM ezsession, ezbasket 00111 WHERE ezbasket.session_id = ezsession.session_key (+) AND 00112 ezsession.session_key IS NULL"; 00113 } 00114 else 00115 { 00116 $sql = "SELECT id, productcollection_id 00117 FROM ezsession 00118 RIGHT JOIN ezbasket 00119 ON ezbasket.session_id = ezsession.session_key 00120 WHERE ezsession.session_key IS NULL"; 00121 } 00122 if ( $limit === false ) 00123 $limit = eZDBGarbageCollector::ITEM_LIMIT; 00124 $end = false; 00125 if ( is_numeric( $maxTime ) ) 00126 $end = time() + $maxTime; 00127 00128 //include_once( 'kernel/classes/ezproductcollection.php' ); 00129 00130 do 00131 { 00132 $rows = $db->arrayQuery( $sql, array( 'offset' => 0, 'limit' => $limit ) ); 00133 if ( count( $rows ) == 0 ) 00134 break; 00135 00136 $productCollectionIDList = array(); 00137 $idList = array(); 00138 foreach ( $rows as $row ) 00139 { 00140 $idList[] = (int)$row['id']; 00141 $productCollectionIDList[] = (int)$row['productcollection_id']; 00142 } 00143 eZProductCollection::cleanupList( $productCollectionIDList ); 00144 00145 $ids = implode( ', ', $idList ); 00146 $db->query( "DELETE FROM ezbasket WHERE id IN ( $ids )" ); 00147 00148 // Stop when we used up our time 00149 if ( $end !== false and time() > $end ) 00150 break; 00151 00152 // Sleep a little if required, reduces load on server 00153 if ( $sleepTime !== false ) 00154 sleep( $sleepTime ); 00155 00156 } while ( true ); 00157 } 00158 00159 /*! 00160 Removes entries from ezproductcollection which is missing relations to other tables. 00161 00162 \param $maxTime The maximum number of seconds the collector should run. 00163 If set to \c false or \c true it will continue until all garbage is collected, 00164 \c false means to try the fastest way possible (may use lots of resources). 00165 \param $sleepTime Controls how many seconds it will sleep between each batch of cleanup, 00166 setting it to \c false means that it should never sleep. 00167 \param $limit Controls how many items are cleaned in one batch operation, 00168 a value of \c false means to use default value. 00169 00170 \note The function will most likely use a little more time than \a $maxTime so 00171 don't depend on it to be accurate. 00172 00173 \note The current code hardcodes the related tables. 00174 00175 \warning This code may be very slow on large sites. 00176 00177 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00178 the calls within a db transaction; thus within db->begin and db->commit. 00179 */ 00180 function collectProductCollections( $maxTime = false, $sleepTime = false, $limit = false ) 00181 { 00182 $db = eZDB::instance(); 00183 00184 // Create a temporary table for filling in collection ids 00185 // that are in use 00186 if ( $db->databaseName() == 'mysql' ) 00187 $db->query( "DROP TABLE IF EXISTS ezproductcollection_used" ); 00188 $db->query( "CREATE TABLE ezproductcollection_used ( id int )" ); 00189 00190 // Fill in collections used by orders 00191 $db->query( "INSERT INTO ezproductcollection_used (id) SELECT productcollection_id FROM ezorder" ); 00192 00193 // Fill in collections used by wish lists 00194 $db->query( "INSERT INTO ezproductcollection_used (id) SELECT productcollection_id FROM ezwishlist" ); 00195 00196 // Fill in collections used by baskets 00197 $db->query( "INSERT INTO ezproductcollection_used (id) SELECT productcollection_id FROM ezbasket" ); 00198 00199 // Create the index for faster selects 00200 $db->query( "CREATE INDEX ezproductcollection_used_id on ezproductcollection_used( id )" ); 00201 00202 if ( $maxTime === false and $db->hasRequiredServerVersion( '4.0', 'mysql' ) ) 00203 { 00204 // Delete entries which are not in ezproductcollection_used 00205 $db->query( "DELETE FROM ezproductcollection, ezproductcollection_item, ezproductcollection_item_opt 00206 USING ezproductcollection_used 00207 RIGHT JOIN ezproductcollection 00208 ON ezproductcollection_used.id = ezproductcollection.id 00209 LEFT JOIN ezproductcollection_item 00210 ON ezproductcollection.id = ezproductcollection_item.productcollection_id 00211 LEFT JOIN ezproductcollection_item_opt 00212 ON ezproductcollection_item.id = ezproductcollection_item_opt.item_id 00213 WHERE ezproductcollection_used.id IS NULL" ); 00214 $db->query( $sql ); 00215 00216 // Remove the temporary table 00217 $db->query( "DROP TABLE ezproductcollection_used" ); 00218 00219 return; 00220 } 00221 00222 // Find all product collections which are not in use 00223 if ( $db->hasRequiredServerVersion( '8', 'oracle' ) ) 00224 { 00225 $sql = "SELECT ezproductcollection.id 00226 FROM ezproductcollection_used, ezproductcollection 00227 WHERE ezproductcollection_used.id = ezproductcollection.id (+) AND 00228 ezproductcollection_used.id IS NULL"; 00229 } 00230 else 00231 { 00232 $sql = "SELECT ezproductcollection.id 00233 FROM ezproductcollection_used 00234 RIGHT JOIN ezproductcollection 00235 ON ezproductcollection_used.id = ezproductcollection.id 00236 WHERE ezproductcollection_used.id IS NULL"; 00237 } 00238 if ( $limit === false ) 00239 $limit = eZDBGarbageCollector::ITEM_LIMIT; 00240 $end = false; 00241 if ( is_numeric( $maxTime ) ) 00242 $end = time() + $maxTime; 00243 00244 //include_once( 'kernel/classes/ezproductcollectionitem.php' ); 00245 00246 do 00247 { 00248 $rows = $db->arrayQuery( $sql, array( 'offset' => 0, 'limit' => $limit ) ); 00249 if ( count( $rows ) == 0 ) 00250 break; 00251 00252 $idList = array(); 00253 foreach ( $rows as $row ) 00254 { 00255 $idList[] = (int)$row['id']; 00256 } 00257 eZProductCollectionItem::cleanupList( $idList ); 00258 00259 $ids = implode( ', ', $idList ); 00260 $db->query( "DELETE FROM ezproductcollection WHERE id IN ( $ids )" ); 00261 $db->query( "DELETE FROM ezproductcollection_used WHERE id IN ( $ids )" ); 00262 00263 // Stop when we used up our time 00264 if ( $end !== false and time() > $end ) 00265 break; 00266 00267 // Sleep a little if required, reduces load on server 00268 if ( $sleepTime !== false ) 00269 sleep( $sleepTime ); 00270 00271 } while ( true ); 00272 00273 // Remove the temporary table 00274 $db->query( "DROP TABLE ezproductcollection_used" ); 00275 } 00276 00277 /*! 00278 \static 00279 Removes all product collection items which are missing a product collection. 00280 00281 \param $maxTime The maximum number of seconds the collector should run. 00282 If set to \c false or \c true it will continue until all garbage is collected, 00283 \c false means to try the fastest way possible (may use lots of resources). 00284 \param $sleepTime Controls how many seconds it will sleep between each batch of cleanup, 00285 setting it to \c false means that it should never sleep. 00286 \param $limit Controls how many items are cleaned in one batch operation, 00287 a value of \c false means to use default value. 00288 00289 \note The function will most likely use a little more time than \a $maxTime so 00290 don't depend on it to be accurate. 00291 00292 \note This will also remove the product collection item option the item is using. 00293 00294 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00295 the calls within a db transaction; thus within db->begin and db->commit. 00296 */ 00297 function collectProductCollectionItems( $maxTime = false, $sleepTime = false, $limit = false ) 00298 { 00299 $db = eZDB::instance(); 00300 00301 if ( $maxTime === false and $db->hasRequiredServerVersion( '4.0', 'mysql' ) ) 00302 { 00303 $sql = "DELETE FROM ezproductcollection_item, ezproductcollection_item_opt 00304 USING ezproductcollection 00305 LEFT JOIN ezproductcollection_item 00306 ON ezproductcollection.id = ezproductcollection_item.productcollection_id 00307 LEFT JOIN ezproductcollection_item_opt 00308 ON ezproductcollection_item.id = ezproductcollection_item_opt.item_id 00309 WHERE ezproductcollection.id IS NULL"; 00310 $db->query( $sql ); 00311 00312 return; 00313 } 00314 00315 // Find all items which are lacking a collection (db leaks) 00316 if ( $db->hasRequiredServerVersion( '8', 'oracle' ) ) 00317 { 00318 $sql = "SELECT ezproductcollection_item.productcollection_id 00319 FROM ezproductcollection, ezproductcollection_item 00320 WHERE ezproductcollection.id = ezproductcollection_item.productcollection_id (+) AND 00321 ezproductcollection.id IS NULL"; 00322 } 00323 else 00324 { 00325 $sql = "SELECT ezproductcollection_item.productcollection_id 00326 FROM ezproductcollection 00327 RIGHT JOIN ezproductcollection_item 00328 ON ezproductcollection.id = ezproductcollection_item.productcollection_id 00329 WHERE ezproductcollection.id IS NULL"; 00330 } 00331 if ( $limit === false ) 00332 $limit = eZDBGarbageCollector::ITEM_LIMIT; 00333 $end = false; 00334 if ( is_numeric( $maxTime ) ) 00335 $end = time() + $maxTime; 00336 00337 //include_once( 'kernel/classes/ezproductcollectionitemoption.php' ); 00338 00339 do 00340 { 00341 $rows = $db->arrayQuery( $sql, array( 'offset' => 0, 'limit' => $limit ) ); 00342 if ( count( $rows ) == 0 ) 00343 break; 00344 00345 $idList = array(); 00346 foreach ( $rows as $row ) 00347 { 00348 $idList[] = (int)$row['productcollection_id']; 00349 } 00350 eZProductCollectionItemOption::cleanupList( $idList ); 00351 00352 $ids = implode( ', ', $idList ); 00353 $db->query( "DELETE FROM ezproductcollection_item WHERE productcollection_id IN ( $ids )" ); 00354 00355 // Stop when we used up our time 00356 if ( $end !== false and time() > $end ) 00357 break; 00358 00359 // Sleep a little if required, reduces load on server 00360 if ( $sleepTime !== false ) 00361 sleep( $sleepTime ); 00362 00363 } while ( true ); 00364 } 00365 00366 /*! 00367 \static 00368 Removes all product collection item options which are missing a product collection item. 00369 00370 \param $maxTime The maximum number of seconds the collector should run. 00371 If set to \c false or \c true it will continue until all garbage is collected, 00372 \c false means to try the fastest way possible (may use lots of resources). 00373 \param $sleepTime Controls how many seconds it will sleep between each batch of cleanup, 00374 setting it to \c false means that it should never sleep. 00375 \param $limit Controls how many items are cleaned in one batch operation, 00376 a value of \c false means to use default value. 00377 00378 \note The function will most likely use a little more time than \a $maxTime so 00379 don't depend on it to be accurate. 00380 00381 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00382 the calls within a db transaction; thus within db->begin and db->commit. 00383 */ 00384 function collectProductCollectionItemOptions( $maxTime = false, $sleepTime = false, $limit = false ) 00385 { 00386 $db = eZDB::instance(); 00387 00388 if ( $maxTime === false and $db->hasRequiredServerVersion( '4.0', 'mysql' ) ) 00389 { 00390 $sql = "DELETE FROM ezproductcollection_item_opt 00391 USING ezproductcollection_item 00392 LEFT JOIN ezproductcollection_item_opt 00393 ON ezproductcollection_item.id = ezproductcollection_item_opt.item_id 00394 WHERE ezproductcollection_item.id IS NULL"; 00395 $db->query( $sql ); 00396 00397 return; 00398 } 00399 00400 // Find all items which are lacking a collection (db leaks) 00401 if ( $db->hasRequiredServerVersion( '8', 'oracle' ) ) 00402 { 00403 $sql = "SELECT ezproductcollection_item_opt.item_id 00404 FROM ezproductcollection_item, ezproductcollection_item_opt 00405 WHERE ezproductcollection_item.id = ezproductcollection_item_opt.item_id (+) AND 00406 ezproductcollection_item.id IS NULL"; 00407 } 00408 else 00409 { 00410 $sql = "SELECT ezproductcollection_item_opt.item_id 00411 FROM ezproductcollection_item 00412 RIGHT JOIN ezproductcollection_item_opt 00413 ON ezproductcollection_item.id = ezproductcollection_item_opt.item_id 00414 WHERE ezproductcollection_item.id IS NULL"; 00415 } 00416 if ( $limit === false ) 00417 $limit = eZDBGarbageCollector::ITEM_LIMIT; 00418 $end = false; 00419 if ( is_numeric( $maxTime ) ) 00420 $end = time() + $maxTime; 00421 00422 do 00423 { 00424 $rows = $db->arrayQuery( $sql, array( 'offset' => 0, 'limit' => $limit ) ); 00425 if ( count( $rows ) == 0 ) 00426 break; 00427 00428 $idList = array(); 00429 foreach ( $rows as $row ) 00430 { 00431 $idList[] = (int)$row['item_id']; 00432 } 00433 00434 $ids = implode( ', ', $idList ); 00435 $db->query( "DELETE FROM ezproductcollection_item_opt WHERE item_id IN ( $ids )" ); 00436 00437 // Stop when we used up our time 00438 if ( $end !== false and time() > $end ) 00439 break; 00440 00441 // Sleep a little if required, reduces load on server 00442 if ( $sleepTime !== false ) 00443 sleep( $sleepTime ); 00444 00445 } while ( true ); 00446 } 00447 } 00448 00449 ?>