Exponential Basic 2.4.0.1 Exponential Basic CMS — PHP Class Reference

ezdfsfilehandler.php
Go to the documentation of this file.
1 <?php
27 class eZDFSFileHandler implements eZClusterFileHandlerInterface, ezpDatabaseBasedClusterFileHandler
28 {
34 const LOCAL_CACHE = 1;
35
41 const INFOCACHE_MAX = 200;
42
53 function __construct( $filePath = false )
54 {
55 if ( self::$nonExistantStaleCacheHandling === null )
56 {
57 $fileINI = eZINI::instance( 'file.ini' );
58 self::$nonExistantStaleCacheHandling = $fileINI->variable( "ClusteringSettings", "NonExistantStaleCacheHandling" );
59 unset( $fileINI );
60 }
61
62 // DB Backend init
63 if ( self::$dbbackend === null )
64 {
65 self::$dbbackend = eZExtension::getHandlerClass(
66 new ezpExtensionOptions(
67 array( 'iniFile' => 'file.ini',
68 'iniSection' => 'eZDFSClusteringSettings',
69 'iniVariable' => 'DBBackend' ) ) );
70 self::$dbbackend->_connect( false );
71
72 $fileINI = eZINI::instance( 'file.ini' );
73 if (
74 $fileINI->variable( 'ClusterEventsSettings', 'ClusterEvents' ) === 'enabled'
75 && self::$dbbackend instanceof eZClusterEventNotifier
76 )
77 {
78 $listener = eZExtension::getHandlerClass(
79 new ezpExtensionOptions(
80 array(
81 'iniFile' => 'file.ini',
82 'iniSection' => 'ClusterEventsSettings',
83 'iniVariable' => 'Listener',
84 'handlerParams' => array( new eZClusterEventLoggerEzdebug() )
85 )
86 )
87 );
88
89 if ( $listener instanceof eZClusterEventListener )
90 {
91 self::$dbbackend->registerListener( $listener );
92 $listener->initialize();
93 }
94 }
95 }
96
97 if ( $filePath !== false )
98 {
99 $filePath = self::cleanPath( $filePath );
100 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::ctor( '$filePath' )" );
101 }
102 else
103 {
104 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::ctor()" );
105 }
106
107 $this->filePath = $filePath;
108 }
109
113 public function disconnect()
114 {
115 if ( self::$dbbackend !== null )
116 {
117 self::$dbbackend->_disconnect();
118 self::$dbbackend= null;
119 }
120 }
121
128 public function loadMetaData( $force = false )
129 {
130 // Fetch metadata.
131 if ( $this->filePath === false )
132 return;
133
134 if ( $force && isset( $GLOBALS['eZClusterInfo'][$this->filePath] ) )
135 unset( $GLOBALS['eZClusterInfo'][$this->filePath] );
136
137 // Checks for metadata stored in memory, useful for repeated access
138 // to the same file in one request
139 // TODO: On PHP5 turn into static member
140 if ( isset( $GLOBALS['eZClusterInfo'][$this->filePath] ) )
141 {
142 $GLOBALS['eZClusterInfo'][$this->filePath]['cnt'] += 1;
143 $this->_metaData = $GLOBALS['eZClusterInfo'][$this->filePath]['data'];
144 return;
145 }
146
147 $metaData = self::$dbbackend->_fetchMetadata( $this->filePath );
148 if ( $metaData )
149 $this->_metaData = $metaData;
150 else
151 $this->_metaData = false;
152
153 // Clean up old entries if the maximum count is reached
154 if ( isset( $GLOBALS['eZClusterInfo'] ) &&
155 count( $GLOBALS['eZClusterInfo'] ) >= self::INFOCACHE_MAX )
156 {
157 usort( $GLOBALS['eZClusterInfo'], function ( $a, $b ) {
158 $a = $a['cnt'];
159 $b = $b['cnt'];
160
161 if ( $a == $b )
162 {
163 return 0;
164 }
165
166 return $a > $b ? -1 : 1;
167 });
168 array_pop( $GLOBALS['eZClusterInfo'] );
169 }
170 $GLOBALS['eZClusterInfo'][$this->filePath] = array( 'cnt' => 1,
171 'data' => $metaData );
172 }
173
185 public function fileStore( $filePath, $scope = false, $delete = false, $datatype = false )
186 {
187 $filePath = self::cleanPath( $filePath );
188 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileStore( '$filePath' )" );
189
190 if ( $scope === false )
191 $scope = 'UNKNOWN_SCOPE';
192
193 if ( $datatype === false )
194 $datatype = 'misc';
195
196 self::$dbbackend->_store( $filePath, $datatype, $scope );
197
198 if ( $delete )
199 @unlink( $filePath );
200 }
201
213 public function fileStoreContents( $filePath, $contents, $scope = false, $datatype = false )
214 {
215 $filePath = self::cleanPath( $filePath );
216 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileStoreContents( '$filePath' )" );
217
218 if ( $scope === false )
219 $scope = 'UNKNOWN_SCOPE';
220
221 if ( $datatype === false )
222 $datatype = 'misc';
223
224 // the file is stored with the current time as mtime
225 self::$dbbackend->_storeContents( $filePath, $contents, $scope, $datatype );
226 }
227
237 public function storeContents( $contents, $scope = false, $datatype = false, $storeLocally = false )
238 {
239 if ( $scope === false )
240 $scope = 'UNKNOWN_SCOPE';
241
242 if ( $datatype === false )
243 $datatype = 'misc';
244
245 $filePath = $this->filePath;
246 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::storeContents( '$filePath' )" );
247
248 // the file is stored with the current time as mtime
249 $result = self::$dbbackend->_storeContents( $filePath, $contents, $scope, $datatype );
250 if ( $result && $storeLocally )
251 {
252 eZFile::create( basename( $filePath ), dirname( $filePath ), $contents, true );
253 }
254
255 return $result;
256 }
257
265 function fileFetch( $filePath )
266 {
267 $filePath = self::cleanPath( $filePath );
268 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileFetch( '$filePath' )" );
269
270 return self::$dbbackend->_fetch( $filePath );
271 }
272
273 /*public function fileFetch( $filePath )
274 {
275 $filePath = self::cleanPath( $filePath );
276 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileFetch( '$filePath' )" );
277
278 switch ( self::$dbbackend->_prepareFetch( $filePath ) )
279 {
280 // READ_STATUS_OK: SLOCK granted, DFS read OK
281 case self::READ_STATUS_OK:
282 {
283 // copy file from DFS to FS
284
285 // release the SLOCK on the file
286 self::$dbbackend->_endFetch( $filePath );
287 } break;
288
289 // READ_STATUS_STALE: SLOCK granted, local version is prefered
290 case self::READ_STATUS_STALE:
291 {
292
293 }
294 }
295 }*/
296
303 public function fetchUnique()
304 {
305 $filePath = $this->filePath;
306 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fetchUnique( '$filePath' )" );
307
308 $fetchedFilePath = self::$dbbackend->_fetch( $filePath, true );
309 $this->uniqueName = $fetchedFilePath;
310 return $fetchedFilePath;
311 }
312
317 function fetch( $noLocalCache = false )
318 {
319 return $this->fileFetch( $this->filePath );
320 }
321
326 function fileFetchContents( $filePath )
327 {
328 $filePath = self::cleanPath( $filePath );
329 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileFetchContents( '$filePath' )" );
330
331 $contents = self::$dbbackend->_fetchContents( $filePath );
332 return $contents;
333 }
334
339 function fetchContents()
340 {
341 $filePath = $this->filePath;
342 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileFetchContents( '$filePath' )" );
343 $contents = self::$dbbackend->_fetchContents( $filePath );
344 return $contents;
345 }
346
413 function processCache( $retrieveCallback, $generateCallback = null, $ttl = null, $expiry = null, $extraData = null )
414 {
415 $forceDB = false;
416 $curtime = time();
417 $tries = 0;
418 $noCache = false;
419
420 if ( $expiry < 0 )
421 $expiry = null;
422 if ( $ttl < 0 )
423 $ttl = null;
424
425 // Main loop
426 while ( true )
427 {
428 // Start read checks
429 // Note: The while loop is used to make it easier to break out of the "read" code
430 while ( true )
431 {
432 // No retrieve method so go directly to generate+store
433 if ( $retrieveCallback === null || !$this->filePath )
434 break;
435
436 if ( !self::LOCAL_CACHE )
437 {
438 $forceDB = true;
439 }
440 else
441 {
442 if ( $this->isLocalFileExpired( $expiry, $curtime, $ttl ) )
443 {
444 // if we are in stale cache mode, we only forceDB if the
445 // file does not exist at all
446 if ( $this->useStaleCache )
447 {
448 if ( !file_exists( $this->filePath ) )
449 {
450 eZDebugSetting::writeDebug( 'kernel-clustering', "Local file '{$this->filePath}' does not exist and can not be used for stale cache. Checking with DB", __METHOD__ );
451 $forceDB = true;
452
453 // forceDB + useStaleCache means that we should check for the DB file.
454 }
455 }
456 else
457 {
458 // Local file is older than global timestamp, check with DB
459 eZDebugSetting::writeDebug( 'kernel-clustering', "Local file (mtime=" . @filemtime( $this->filePath ) . ") is older than timestamp ($expiry) and ttl($ttl), check with DB", __METHOD__ );
460 $forceDB = true;
461 }
462 }
463 }
464
465 if ( !$forceDB )
466 {
467 // check if DB file is deleted
468 if ( !$this->useStaleCache && ( $this->metaData === false || $this->metaData['mtime'] < 0 ) )
469 {
470 if ( $generateCallback !== false )
471 eZDebugSetting::writeDebug( 'kernel-clustering', "Database file is deleted, need to regenerate data", __METHOD__ );
472 else
473 eZDebugSetting::writeDebug( 'kernel-clustering', "Database file is deleted, cannot get data", __METHOD__ );
474 break;
475 }
476
477 // check if FS file is older than DB file
478 if ( !$this->useStaleCache && $this->isLocalFileExpired( $this->metaData['mtime'], $curtime, $ttl ) )
479 {
480 eZDebugSetting::writeDebug( 'kernel-clustering', "Local file (mtime=" . @filemtime( $this->filePath ) . ") is older than DB, checking with DB", __METHOD__ );
481 $forceDB = true;
482 }
483 else
484 {
485 if ( $this->useStaleCache )
486 {
487 // to get the retrieve callback to accept the cache file,
488 // we force its mtime to the current time
489 $mtime = $curtime;
490 eZDebugSetting::writeDebug( 'kernel-clustering', "Processing local stale cache file {$this->filePath}", __METHOD__ );
491 }
492 else
493 {
494 $mtime = filemtime( $this->filePath );
495 eZDebugSetting::writeDebug( 'kernel-clustering', "Processing local cache file {$this->filePath}", __METHOD__ );
496 }
497
498 $args = array( $this->filePath, $mtime );
499 if ( $extraData !== null )
500 $args[] = $extraData;
501 $retval = call_user_func_array( $retrieveCallback, $args );
502 if ( $retval instanceof eZClusterFileFailure )
503 {
504 break;
505 }
506 return $retval;
507 }
508 }
509
510 if ( $forceDB )
511 {
512 // stale cache, and no DB or FS file available
513 if ( $this->useStaleCache && $this->metaData === false )
514 {
515 // configuration says we have to generate our own version
516 if ( $this->nonExistantStaleCacheHandling[ $this->cacheType ] == 'generate' )
517 {
518 // no cache available, but a generate callback exists, skip to generation
519 if ( $generateCallback !== false )
520 {
521 eZDebugSetting::writeDebug( 'kernel-clustering', "Database file is deleted, need to regenerate data" );
522 break;
523 }
524 // if no generate callback exists, we can directly skip the main loop
525 else
526 {
527 eZDebugSetting::writeDebug( 'kernel-clustering', "Database file is deleted, cannot get data" );
528 break 2;
529 }
530 }
531 // wait for the generating process to be finished (or timedout)
532 else
533 {
534 while ( $this->remainingCacheGenerationTime-- >= 0 )
535 {
536 // we don't know if the file gets generated on the current
537 // frontend or not. However, we can still try the FS cache
538 // first, then the DB cache if FS is not found, since this
539 // will be much more efficient
540 if ( !file_exists( $this->filePath ) )
541 {
542 $this->loadMetaData( true );
543 if ( $this->metaData === false )
544 {
545 sleep( 1 );
546 continue;
547 }
548 else
549 {
550 break;
551 }
552 }
553 else
554 {
555 break;
556 }
557 }
558
559 // if we reached this point, it means that we are over the estimated timeout value
560 // we try to take the generation over by starting the cache generation. IF this
561 // fails again, it is probably because another waiting process has taken the generation
562 // over. Maybe add a counter here to prevent some kind of death loop ?
563 eZDebugSetting::writeDebug( 'kernel-clustering', "Checking if {$this->filePath} was generating during the wait loop", __METHOD__ );
564 $this->loadMetaData( true );
565 $this->useStaleCache = false;
566 $this->remainingCacheGenerationTime = false;
567 $forceDB = false;
568
569 // this continues to the main loop 'while (true)'
570 continue 2;
571 }
572 }
573 // no stale cache, and expired DB file
574 elseif ( !$this->useStaleCache && ( $this->metaData === false || $this->isDBFileExpired( $expiry, $curtime, $ttl ) ) ) // no stalecache, and no DB file, generation is required
575 {
576 // no cache available, but a generate callback exists, skip to generation
577 if ( $generateCallback !== false )
578 {
579 eZDebugSetting::writeDebug( 'kernel-clustering', "Database file is deleted, need to regenerate data", __METHOD__ );
580
581 // we break out of one loop so that the generateCallback is called
582 break;
583 }
584 // if no generate callback exists, we can directly skip the main loop
585 else
586 {
587 eZDebugSetting::writeDebug( 'kernel-clustering', "Database file is deleted, cannot get data", __METHOD__ );
588
589 // we break out of two loops so that we directly exit the method and have
590 // the rest of execution generate the data
591 break 2;
592 }
593 }
594 else
595 {
596 eZDebugSetting::writeDebug( 'kernel-clustering', "Callback from DB file {$this->filePath}", __METHOD__ );
597 if ( self::LOCAL_CACHE )
598 {
599 if ( $this->fetch() === false )
600 {
601 return new eZClusterFileFailure( eZClusterFileFailure::FILE_RETRIEVAL_FAILED, "Failed retrieving file $this->filePath from DFS." );
602 }
603
604 // Figure out which mtime to use for new file, must be larger than
605 // mtime in DB at least.
606 $mtime = $this->metaData['mtime'] + 1;
607 $localmtime = @filemtime( $this->filePath );
608 $mtime = max( $mtime, $localmtime );
609 touch( $this->filePath, $mtime, $mtime );
610 clearstatcache(); // Needed because of touch() call
611
612 $args = array( $this->filePath, $mtime );
613 if ( $extraData !== null )
614 $args[] = $extraData;
615 $retval = call_user_func_array( $retrieveCallback, $args );
616 if ( $retval instanceof eZClusterFileFailure )
617 {
618 break;
619 }
620 return $retval;
621 }
622 else
623 {
624 $uniquePath = $this->fetchUnique();
625
626 $args = array( $uniquePath, $this->metaData['mtime'] );
627 if ( $extraData !== null )
628 $args[] = $extraData;
629 $retval = call_user_func_array( $retrieveCallback, $args );
630 $this->fileDeleteLocal( $uniquePath );
631 if ( $retval instanceof eZClusterFileFailure )
632 break;
633 return $retval;
634 }
635 }
636 eZDebugSetting::writeDebug( 'kernel-clustering', "Database file does not exist, need to regenerate data", __METHOD__ );
637 break;
638 }
639 }
640
641 if ( $tries >= 2 )
642 {
643 eZDebugSetting::writeDebug( 'kernel-clustering', "Reading was retried $tries times and reached the maximum, returning null", __METHOD__ );
644 return null;
645 }
646
647 // Generation part starts here
648 if ( isset( $retval ) && $retval instanceof eZClusterFileFailure )
649 {
650 // This error means that the retrieve callback told
651 // us NOT to enter generation mode and therefore NOT to store this
652 // cache.
653 // This parameter will then be passed to the generate callback,
654 // and this will set store to false
655 if ( $retval->errno() == 3 )
656 {
657 $noCache = true;
658 }
659
660 // check for non-expiry error codes
661 elseif ( $retval->errno() != 1 )
662 {
663 eZDebug::writeError( "Failed to retrieve data from callback", __METHOD__ );
664 return null;
665 }
666 $message = $retval->message();
667 if ( strlen( $message ) > 0 )
668 {
669 eZDebugSetting::writeDebug( 'kernel-clustering', $retval->message(), __METHOD__ );
670 }
671 // the retrieved data was expired so we need to generate it, let's continue
672 }
673
674 // We need to lock if we have a generate-callback or
675 // the generation is deferred to the caller.
676 // Note: false means no generation, while null means that generation
677 // is deferred to the processing that follows (f.i. cache-blocks)
678 if ( $generateCallback !== false && $this->filePath )
679 {
680 if ( !$this->useStaleCache && !$noCache )
681 {
682 $res = $this->startCacheGeneration();
683 if ( $res !== true )
684 {
685 eZDebugSetting::writeDebug( 'kernel-clustering', "{$this->filePath} is being generated, switching to staleCache mode", __METHOD__ );
686 $this->useStaleCache = true;
687 $this->remainingCacheGenerationTime = $res;
688 $forceDB = false;
689 continue;
690 }
691 }
692
693 // File in DB is outdated or non-existing, call write-callback to generate content
694 if ( $generateCallback )
695 {
696 $args = array( $this->filePath );
697 if ( $noCache )
698 $extraData['noCache'] = $noCache;
699 if ( $extraData !== null )
700 $args[] = $extraData;
701 $fileData = call_user_func_array( $generateCallback, $args );
702 return $this->storeCache( $fileData );
703 }
704 }
705
706 break;
707 } // End main loop
708
709 return new eZClusterFileFailure( 2, "Manual generation of file data is required, calling storeCache is required" );
710 }
711
725 public static function isFileExpired( $fname, $mtime, $expiry, $curtime, $ttl )
726 {
727 if ( $mtime == false or $mtime < 0 )
728 {
729 return true;
730 }
731 elseif ( $ttl === null )
732 {
733 return $mtime < $expiry;
734 }
735 else
736 {
737 return $mtime < max( $expiry, $curtime - $ttl );
738 }
739 }
740
749 public function isExpired( $expiry, $curtime, $ttl )
750 {
751 return self::isFileExpired( $this->filePath, $this->metaData['mtime'], $expiry, $curtime, $ttl );
752 }
753
761 public function isLocalFileExpired( $expiry, $curtime, $ttl )
762 {
763 return self::isFileExpired( $this->filePath, @filemtime( $this->filePath ), $expiry, $curtime, $ttl );
764 }
765
773 public function isDBFileExpired( $expiry, $curtime, $ttl )
774 {
775 $mtime = isset( $this->metaData['mtime'] ) ? $this->metaData['mtime'] : 0;
776 return self::isFileExpired( $this->filePath, $mtime, $expiry, $curtime, $ttl );
777 }
778
789 public function storeCache( $fileData )
790 {
791 $scope = false;
792 $datatype = false;
793 $binaryData = null;
794 $fileContent = null;
795 $store = true;
796 $storeCache = false;
797
798 if ( is_array( $fileData ) )
799 {
800 if ( isset( $fileData['scope'] ) )
801 $scope = $fileData['scope'];
802 if ( isset( $fileData['datatype'] ) )
803 $datatype = $fileData['datatype'];
804 if ( isset( $fileData['content'] ) )
805 $fileContent = $fileData['content'];
806 if ( isset( $fileData['binarydata'] ) )
807 $binaryData = $fileData['binarydata'];
808 if ( isset( $fileData['store'] ) )
809 $store = $fileData['store'];
810 }
811 else
812 $binaryData = $fileData;
813
814 // This checks if we entered timeout and got our generating file stolen
815 // If this happens, we don't store our cache
816 if ( $store and $this->checkCacheGenerationTimeout() )
817 $storeCache = true;
818
819 $result = null;
820 if ( $binaryData === null &&
821 $fileContent === null )
822 {
823 eZDebug::writeError( "Write callback need to set the 'content' or 'binarydata' entry for '{$this->filePath}'", __METHOD__ );
824 $this->abortCacheGeneration();
825 return null;
826 }
827
828 if ( $binaryData === null )
829 $binaryData = "<" . "?php\n\treturn ". var_export( $fileContent, true ) . ";\n?" . ">\n";
830
831 if ( $fileContent === null )
832 $result = $binaryData;
833 else
834 $result = $fileContent;
835
836 if ( !$this->filePath )
837 return $result;
838
839 // no store advice from cache generation timeout or disabled viewcache,
840 // we just return the result
841 if ( !$storeCache )
842 {
843 eZDebugSetting::writeDebug( 'kernel-clustering',
844 "Not storing this cache", __METHOD__ );
845 $this->abortCacheGeneration();
846 return $result;
847 }
848
849 // stale cache handling: we just return the result, no lock has been set
850 if ( $this->useStaleCache )
851 {
852 eZDebugSetting::writeDebug( 'kernel-clustering', "Stalecache mode enabled for this cache",
853 "dfs::storeCache( {$this->filePath} )" );
854 // we write the generated cache to disk if it does not exist yet,
855 // to speed up the next uncached operation
856 // This file will be overwritten by the real file
857 clearstatcache();
858 if ( !file_exists( $this->filePath ) )
859 {
860 eZDebugSetting::writeDebug( 'kernel-clustering', "Writing stale file content to local file {$this->filePath}", __METHOD__ );
861 eZFile::create( basename( $this->filePath ), dirname( $this->filePath ), $binaryData, true );
862 }
863 return $result;
864 }
865
866 // Check if we are allowed to store the data, if not just return the result
867 if ( !$store )
868 {
869 $this->abortCacheGeneration();
870 return $result;
871 }
872
873 // Distinguish bool from eZClusterFileFailure, and call abortCacheGeneration()
874 $storeContentsResult = $this->storeContents( $binaryData, $scope, $datatype, $storeLocally = false );
875
876 // Cache was stored, we end cache generation
877 if ( $storeContentsResult === true )
878 {
879 $this->endCacheGeneration();
880 }
881 // An unexpected error occured, we abort generation
882 else if ( $storeContentsResult instanceof eZMySQLBackendError )
883 {
884 $this->abortCacheGeneration();
885 }
886 // We don't do anything if false (not stored for known reasons) has been returned
887
888 return $result;
889 }
890
905 function processFile( $callback, $expiry = false, $extraData = null )
906 {
907 $result = $this->processCache( $callback, false, null, $expiry, $extraData );
908 if ( $result instanceof eZClusterFileFailure )
909 {
910 return null;
911 }
912 return $result;
913 }
914
918 public function stat()
919 {
920 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::stat()" );
921 return $this->metaData;
922 }
923
928 public function size()
929 {
930 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::size()" );
931 return isset( $this->metaData['size'] ) ? (int)$this->metaData['size'] : null;
932 }
933
938 public function dataType()
939 {
940 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::dataType()" );
941 return !empty( $this->metaData['datatype'] ) ? $this->metaData['datatype'] : null;
942 }
943
948 public function mtime()
949 {
950 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::mtime()" );
951 return isset( $this->metaData['mtime'] ) ? (int)$this->metaData['mtime'] : null;
952 }
953
958 public function name()
959 {
960 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::name()" );
961 return $this->filePath;
962 }
963
972 public function fileDeleteByWildcard( $wildcard )
973 {
974 $wildcard = self::cleanPath( $wildcard );
975 eZDebug::writeWarning( "Using " . __METHOD__ . " is not recommended since it has some severe performance issues" );
976 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileDeleteByWildcard( '$wildcard' )" );
977
978 self::$dbbackend->_deleteByWildcard( $wildcard );
979 }
980
991 public function fileDeleteByDirList( $dirList, $commonPath, $commonSuffix )
992 {
993 foreach ( $dirList as $key => $dirItem )
994 {
995 $dirList[$key] = self::cleanPath( $dirItem );
996
997 }
998 $commonPath = self::cleanPath( $commonPath );
999 $commonSuffix = self::cleanPath( $commonSuffix );
1000 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileDeleteByDirList( '" . join( ", ", $dirList ) . "', '$commonPath', '$commonSuffix' )" );
1001
1002 self::$dbbackend->_deleteByDirList( $dirList, $commonPath, $commonSuffix );
1003 }
1004
1015 public function fileDelete( $path, $fnamePart = false )
1016 {
1017 $path = self::cleanPath( $path );
1018 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileDelete( '$path' )" );
1019
1020 if ( $fnamePart === false )
1021 {
1022 self::$dbbackend->_delete( $path );
1023 }
1024 elseif ( $fnamePart === true )
1025 {
1026 self::$dbbackend->_deleteByLike( $path . '/%' );
1027 }
1028 else
1029 {
1030 $fnamePart = self::cleanPath( $fnamePart );
1031 self::$dbbackend->_deleteByLike( $path . '/' . $fnamePart . '%' );
1032 }
1033 }
1034
1040 function delete()
1041 {
1042 $path = $this->filePath;
1043 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::delete( '$path' )" );
1044
1045 self::$dbbackend->_delete( $path );
1046
1047 $this->metaData = null;
1048 }
1049
1053 function fileDeleteLocal( $path )
1054 {
1055 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileDeleteLocal( '$path' )" );
1056 @unlink( self::cleanPath( $path ) );
1057
1058 eZClusterFileHandler::cleanupEmptyDirectories( $path );
1059 }
1060
1064 function deleteLocal()
1065 {
1066 $path = $this->filePath;
1067 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::deleteLocal( '$path' )" );
1068 @unlink( $path );
1069
1070 eZClusterFileHandler::cleanupEmptyDirectories( $path );
1071 }
1072
1097 function purge( $printCallback = false, $microsleep = false, $max = false, $expiry = false )
1098 {
1099 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::purge( '$this->filePath' )" );
1100
1101 $file = $this->filePath;
1102 if ( $max === false )
1103 {
1104 $max = 100;
1105 }
1106 $count = 0;
1112 do
1113 {
1114 // @todo this won't work on windows, make a wrapper that uses
1115 // either usleep or sleep depending on the OS
1116 if ( $count > 0 && $microsleep )
1117 {
1118 usleep( $microsleep ); // Sleep a bit to make the database happier
1119 }
1120 $count = self::$dbbackend->_purgeByLike( $file . "/%", true, $max, $expiry, 'purge' );
1121 self::$dbbackend->_purge( $file, true, $expiry, 'purge' );
1122 if ( $printCallback )
1123 {
1124 call_user_func_array( $printCallback, array( $file, $count ) );
1125 }
1126
1127 // @todo Compare $count to $max. If $count < $max, no more files are to
1128 // be purged, and we can exit the loop
1129 } while ( $count > 0 );
1130
1131 // Remove local copies
1132 if ( is_file( $file ) )
1133 {
1134 @unlink( $file );
1135 }
1136 elseif ( is_dir( $file ) )
1137 {
1138 eZDir::recursiveDelete( $file );
1139 }
1140
1141 eZClusterFileHandler::cleanupEmptyDirectories( $file );
1142 }
1143
1151 function fileExists( $path, $checkDFSFile = false )
1152 {
1153 $path = self::cleanPath( $path );
1154 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileExists( '$path' )" );
1155 return self::$dbbackend->_exists( $path, false, true, $checkDFSFile );
1156 }
1157
1164 function exists( $checkDFSFile = false )
1165 {
1166 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::exists( '$this->filePath' )" );
1167 return self::$dbbackend->_exists( $this->filePath, false, true, $checkDFSFile );
1168 }
1169
1178 function passthrough( $startOffset = 0, $length = false )
1179 {
1180 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::passthrough( '{$this->filePath}', $startOffset, $length )" );
1181 self::$dbbackend->_passThrough( $this->filePath, $startOffset, $length, "dfs::passthrough( '{$this->filePath}'" );
1182 }
1183
1187 function fileCopy( $srcPath, $dstPath )
1188 {
1189 $srcPath = self::cleanPath( $srcPath );
1190 $dstPath = self::cleanPath( $dstPath );
1191 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileCopy( '$srcPath', '$dstPath' )" );
1192
1193 // @todo Add a try... catch block here
1194 self::$dbbackend->_copy( $srcPath, $dstPath );
1195 }
1196
1200 function fileLinkCopy( $srcPath, $dstPath, $symLink )
1201 {
1202 $srcPath = self::cleanPath( $srcPath );
1203 $dstPath = self::cleanPath( $dstPath );
1204 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileLinkCopy( '$srcPath', '$dstPath' )" );
1205
1206 self::$dbbackend->_linkCopy( $srcPath, $dstPath );
1207 }
1208
1212 function fileMove( $srcPath, $dstPath )
1213 {
1214 $srcPath = self::cleanPath( $srcPath );
1215 $dstPath = self::cleanPath( $dstPath );
1216 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileMove( '$srcPath', '$dstPath' )" );
1217
1218 // @todo Catch an exception
1219 self::$dbbackend->_rename( $srcPath, $dstPath );
1220
1221 $this->metaData = null;
1222 }
1223
1228 function move( $dstPath )
1229 {
1230 $dstPath = self::cleanPath( $dstPath );
1231 $srcPath = $this->filePath;
1232
1233 eZDebugSetting::writeDebug( 'kernel-clustering', "dfs::fileMove( '$srcPath', '$dstPath' )" );
1234
1235 self::$dbbackend->_rename( $srcPath, $dstPath );
1236
1237 $this->metaData = null;
1238 }
1239
1251 function getFileList( $scopes = false, $excludeScopes = false, $limit = false, $path = false )
1252 {
1253 eZDebugSetting::writeDebug( 'kernel-clustering',
1254 sprintf( "dfs::getFileList( array( %s ), %d )",
1255 is_array( $scopes ) ? implode( ', ', $scopes ) : '', (int) $excludeScopes ) );
1256 return self::$dbbackend->_getFileList( $scopes, $excludeScopes, $limit, $path );
1257 }
1258
1273 static function cleanPath( $path )
1274 {
1275 if ( !is_string( $path ) )
1276 return $path;
1277 return preg_replace( array( "#[/\\\\]+#", "#/$#" ),
1278 array( "/", "" ),
1279 $path );
1280 }
1281
1290 public function startCacheGeneration()
1291 {
1292 eZDebugSetting::writeDebug( 'kernel-clustering', "Starting cache generation", "dfs::startCacheGeneration( '{$this->filePath}' )" );
1293
1294 $generatingFilePath = $this->filePath . '.generating';
1295 try {
1296 $ret = self::$dbbackend->_startCacheGeneration( $this->filePath, $generatingFilePath );
1297 } catch( RuntimeException $e ) {
1298 eZDebug::writeError( $e->getMessage() );
1299 return false;
1300 }
1301
1302 // generation granted
1303 if ( $ret['result'] == 'ok' )
1304 {
1305 eZClusterFileHandler::addGeneratingFile( $this );
1306 $this->realFilePath = $this->filePath;
1307 $this->filePath = $generatingFilePath;
1308 $this->generationStartTimestamp = $ret['mtime'];
1309 return true;
1310 }
1311 // failure: the file is being generated
1312 elseif ( $ret['result'] == 'ko' )
1313 {
1314 return $ret['remaining'];
1315 }
1316 // unhandled error case, should not happen
1317 else
1318 {
1319 eZLog::write( "An error occured starting cache generation on '$generatingFilePath'", 'cluster.log' );
1320 return false;
1321 }
1322 }
1323
1327 public function endCacheGeneration( $rename = true )
1328 {
1329 if ( $this->realFilePath === null )
1330 {
1331 eZDebugSetting::writeDebug( 'kernel-clustering', "$this->filePath is not generating", "dfs::endCacheGeneration( '{$this->filePath}' )" );
1332 return false;
1333 }
1334
1335 eZDebugSetting::writeDebug( 'kernel-clustering', 'Ending cache generation', "dfs::endCacheGeneration( '{$this->realFilePath}' )" );
1336 try {
1337 if ( self::$dbbackend->_endCacheGeneration( $this->realFilePath, $this->filePath, $rename ) )
1338 {
1339 $this->filePath = $this->realFilePath;
1340 $this->realFilePath = null;
1341 eZClusterFileHandler::removeGeneratingFile( $this );
1342 return true;
1343 }
1344 else
1345 {
1346 return false;
1347 }
1348 } catch( RuntimeException $e ) {
1349 eZDebug::writeError( "An error occured ending cache generation on '$this->realFilePath'", 'cluster.log' );
1350 }
1351 }
1352
1359 public function abortCacheGeneration()
1360 {
1361 eZDebugSetting::writeDebug( 'kernel-clustering', 'Aborting cache generation', "dfs::abortCacheGeneration( '{$this->filePath}' )" );
1362 self::$dbbackend->_abortCacheGeneration( $this->filePath );
1363 $this->filePath = $this->realFilePath;
1364 $this->realFilePath = null;
1365 eZClusterFileHandler::removeGeneratingFile( $this );
1366 }
1367
1373 public function checkCacheGenerationTimeout()
1374 {
1375 eZDebugSetting::writeDebug( 'kernel-clustering', 'Checking cache generation timeout', "dfs::checkCacheGenerationTimeout( '{$this->filePath}' )" );
1376 return self::$dbbackend->_checkCacheGenerationTimeout( $this->filePath, $this->generationStartTimestamp );
1377 }
1378
1383 protected function _cacheType()
1384 {
1385 if ( strpos( $this->filePath, '/cache/content/' ) !== false )
1386 return 'viewcache';
1387 elseif ( strpos( $this->filePath, '/cache/template-block/' ) !== false )
1388 return 'cacheblock';
1389 else
1390 return 'misc';
1391 }
1392
1396 function __get( $propertyName )
1397 {
1398 switch ( $propertyName )
1399 {
1400 case 'cacheType':
1401 {
1402 if ( $this->_cacheType === null )
1403 $this->_cacheType = $this->_cacheType();
1404 return $this->_cacheType;
1405 } break;
1406
1407 // we only fetch metadata when the status of _metadata is unknown.
1408 // it means that the metadata has not been fetched before
1409 // self::resetMetaData can be called to force reload of metadata
1410 // on the next call
1411 case 'metaData':
1412 {
1413 if ( $this->_metaData === null )
1414 {
1415 $this->loadMetaData();
1416 }
1417 return $this->_metaData;
1418 }
1419 }
1420 }
1421
1426 public function requiresClusterizing()
1427 {
1428 return true;
1429 }
1430
1439 public function requiresPurge()
1440 {
1441 return true;
1442 }
1443
1454 public function fetchExpiredItems( $scopes, $limit = array( 0 , 100 ), $expiry = false )
1455 {
1456 return self::$dbbackend->expiredFilesList( $scopes, $limit, $expiry );
1457 }
1458
1459 public function hasStaleCacheSupport()
1460 {
1461 return true;
1462 }
1463
1464 public function applyServerUri( $filePath )
1465 {
1466 return self::$dbbackend->applyServerUri( $filePath );
1467 }
1468
1474 protected static $dbbackend = null;
1475
1480 public $filePath = null;
1481
1487 protected $realFilePath = null;
1488
1494 protected $useStaleCache = false;
1495
1500 protected $remainingCacheGenerationTime = false;
1501
1510 protected $generationStartTimestamp = false;
1511
1520 protected $_metaData = null;
1521
1528 protected static $nonExistantStaleCacheHandling = null;
1529
1534 protected $_cacheType = null;
1535 }
1536 ?>
$message
$message
Definition: admin/message.php:51
eZClusterEventLoggerEzdebug
Definition: ezclustereventloggerezdebug.php:16
eZClusterFileFailure
Definition: ezclusterfilefailure.php:21
eZClusterFileFailure\FILE_RETRIEVAL_FAILED
const FILE_RETRIEVAL_FAILED
Definition: ezclusterfilefailure.php:24
eZClusterFileHandler\addGeneratingFile
static addGeneratingFile( $file)
Definition: ezclusterfilehandler.php:122
eZClusterFileHandler\removeGeneratingFile
static removeGeneratingFile( $file)
Definition: ezclusterfilehandler.php:138
eZClusterFileHandler\cleanupEmptyDirectories
static cleanupEmptyDirectories( $path)
Definition: ezclusterfilehandler.php:103
eZDFSFileHandler
Definition: ezdfsfilehandler.php:28
eZDFSFileHandler\disconnect
disconnect()
Definition: ezdfsfilehandler.php:113
eZDFSFileHandler\$realFilePath
$realFilePath
Definition: ezdfsfilehandler.php:1487
eZDFSFileHandler\loadMetaData
loadMetaData( $force=false)
Definition: ezdfsfilehandler.php:128
eZDFSFileHandler\mtime
mtime()
Definition: ezdfsfilehandler.php:948
eZDFSFileHandler\fileLinkCopy
fileLinkCopy( $srcPath, $dstPath, $symLink)
Definition: ezdfsfilehandler.php:1200
eZDFSFileHandler\move
move( $dstPath)
Definition: ezdfsfilehandler.php:1228
eZDFSFileHandler\$filePath
$filePath
Definition: ezdfsfilehandler.php:1480
eZDFSFileHandler\getFileList
getFileList( $scopes=false, $excludeScopes=false, $limit=false, $path=false)
Definition: ezdfsfilehandler.php:1251
eZDFSFileHandler\fileFetchContents
fileFetchContents( $filePath)
Definition: ezdfsfilehandler.php:326
eZDFSFileHandler\LOCAL_CACHE
const LOCAL_CACHE
Definition: ezdfsfilehandler.php:34
eZDFSFileHandler\__construct
__construct( $filePath=false)
Definition: ezdfsfilehandler.php:53
eZDFSFileHandler\applyServerUri
applyServerUri( $filePath)
Definition: ezdfsfilehandler.php:1464
eZDFSFileHandler\fileDeleteByDirList
fileDeleteByDirList( $dirList, $commonPath, $commonSuffix)
Definition: ezdfsfilehandler.php:991
eZDFSFileHandler\processFile
processFile( $callback, $expiry=false, $extraData=null)
Definition: ezdfsfilehandler.php:905
eZDFSFileHandler\dataType
dataType()
Definition: ezdfsfilehandler.php:938
eZDFSFileHandler\startCacheGeneration
startCacheGeneration()
Definition: ezdfsfilehandler.php:1290
eZDFSFileHandler\$remainingCacheGenerationTime
$remainingCacheGenerationTime
Definition: ezdfsfilehandler.php:1500
eZDFSFileHandler\purge
purge( $printCallback=false, $microsleep=false, $max=false, $expiry=false)
Definition: ezdfsfilehandler.php:1097
eZDFSFileHandler\$useStaleCache
$useStaleCache
Definition: ezdfsfilehandler.php:1494
eZDFSFileHandler\cleanPath
static cleanPath( $path)
Definition: ezdfsfilehandler.php:1273
eZDFSFileHandler\__get
__get( $propertyName)
Definition: ezdfsfilehandler.php:1396
eZDFSFileHandler\fileStore
fileStore( $filePath, $scope=false, $delete=false, $datatype=false)
Definition: ezdfsfilehandler.php:185
eZDFSFileHandler\$dbbackend
static $dbbackend
Definition: ezdfsfilehandler.php:1474
eZDFSFileHandler\endCacheGeneration
endCacheGeneration( $rename=true)
Definition: ezdfsfilehandler.php:1327
eZDFSFileHandler\$nonExistantStaleCacheHandling
static $nonExistantStaleCacheHandling
Definition: ezdfsfilehandler.php:1528
eZDFSFileHandler\size
size()
Definition: ezdfsfilehandler.php:928
eZDFSFileHandler\fileCopy
fileCopy( $srcPath, $dstPath)
Definition: ezdfsfilehandler.php:1187
eZDFSFileHandler\deleteLocal
deleteLocal()
Definition: ezdfsfilehandler.php:1064
eZDFSFileHandler\fileDeleteByWildcard
fileDeleteByWildcard( $wildcard)
Definition: ezdfsfilehandler.php:972
eZDFSFileHandler\fetch
fetch( $noLocalCache=false)
Definition: ezdfsfilehandler.php:317
eZDFSFileHandler\stat
stat()
Definition: ezdfsfilehandler.php:918
eZDFSFileHandler\$_cacheType
$_cacheType
Definition: ezdfsfilehandler.php:1534
eZDFSFileHandler\isDBFileExpired
isDBFileExpired( $expiry, $curtime, $ttl)
Definition: ezdfsfilehandler.php:773
eZDFSFileHandler\fileMove
fileMove( $srcPath, $dstPath)
Definition: ezdfsfilehandler.php:1212
eZDFSFileHandler\requiresPurge
requiresPurge()
Definition: ezdfsfilehandler.php:1439
eZDFSFileHandler\fileDeleteLocal
fileDeleteLocal( $path)
Definition: ezdfsfilehandler.php:1053
eZDFSFileHandler\checkCacheGenerationTimeout
checkCacheGenerationTimeout()
Definition: ezdfsfilehandler.php:1373
eZDFSFileHandler\storeCache
storeCache( $fileData)
Definition: ezdfsfilehandler.php:789
eZDFSFileHandler\storeContents
storeContents( $contents, $scope=false, $datatype=false, $storeLocally=false)
Definition: ezdfsfilehandler.php:237
eZDFSFileHandler\passthrough
passthrough( $startOffset=0, $length=false)
Definition: ezdfsfilehandler.php:1178
eZDFSFileHandler\fetchUnique
fetchUnique()
Definition: ezdfsfilehandler.php:303
eZDFSFileHandler\$_metaData
$_metaData
Definition: ezdfsfilehandler.php:1520
eZDFSFileHandler\hasStaleCacheSupport
hasStaleCacheSupport()
Definition: ezdfsfilehandler.php:1459
eZDFSFileHandler\INFOCACHE_MAX
const INFOCACHE_MAX
Definition: ezdfsfilehandler.php:41
eZDFSFileHandler\fetchExpiredItems
fetchExpiredItems( $scopes, $limit=array(0, 100), $expiry=false)
Definition: ezdfsfilehandler.php:1454
eZDFSFileHandler\fetchContents
fetchContents()
Definition: ezdfsfilehandler.php:339
eZDFSFileHandler\abortCacheGeneration
abortCacheGeneration()
Definition: ezdfsfilehandler.php:1359
eZDFSFileHandler\name
name()
Definition: ezdfsfilehandler.php:958
eZDFSFileHandler\_cacheType
_cacheType()
Definition: ezdfsfilehandler.php:1383
eZDFSFileHandler\fileFetch
fileFetch( $filePath)
Definition: ezdfsfilehandler.php:265
eZDFSFileHandler\fileStoreContents
fileStoreContents( $filePath, $contents, $scope=false, $datatype=false)
Definition: ezdfsfilehandler.php:213
eZDFSFileHandler\$generationStartTimestamp
$generationStartTimestamp
Definition: ezdfsfilehandler.php:1510
eZDFSFileHandler\requiresClusterizing
requiresClusterizing()
Definition: ezdfsfilehandler.php:1426
eZDFSFileHandler\isFileExpired
static isFileExpired( $fname, $mtime, $expiry, $curtime, $ttl)
Definition: ezdfsfilehandler.php:725
eZDFSFileHandler\processCache
processCache( $retrieveCallback, $generateCallback=null, $ttl=null, $expiry=null, $extraData=null)
Definition: ezdfsfilehandler.php:413
eZDFSFileHandler\isLocalFileExpired
isLocalFileExpired( $expiry, $curtime, $ttl)
Definition: ezdfsfilehandler.php:761
eZDFSFileHandler\isExpired
isExpired( $expiry, $curtime, $ttl)
Definition: ezdfsfilehandler.php:749
eZDFSFileHandler\exists
exists( $checkDFSFile=false)
Definition: ezdfsfilehandler.php:1164
eZDFSFileHandler\fileDelete
fileDelete( $path, $fnamePart=false)
Definition: ezdfsfilehandler.php:1015
eZDFSFileHandler\fileExists
fileExists( $path, $checkDFSFile=false)
Definition: ezdfsfilehandler.php:1151
eZDebugSetting\writeDebug
static writeDebug( $conditionName, $string, $label="")
Definition: ezdebugsetting.php:128
eZDebug\writeError
static writeError( $string, $label="", $backgroundClass="")
Definition: ezdebug.php:546
eZDebug\writeWarning
static writeWarning( $string, $label="", $backgroundClass="")
Definition: ezdebug.php:503
eZDir\recursiveDelete
static recursiveDelete( $dir, $rootCheck=true)
Definition: ezdir.php:265
eZExtension\getHandlerClass
static getHandlerClass(ezpExtensionOptions $options)
Definition: ezextension.php:480
eZFile\create
static create( $filename, $directory=false, $data=false, $atomic=false)
Definition: ezfile.php:42
eZLog\write
static write( $message, $logName='common.log', $dir='var/log')
Definition: ezlog.php:30
eZMySQLBackendError
Error class for the MySQL backend (cluster code).
Definition: classes/clusterfilehandlers/dbbackends/mysqlbackenderror.php:18
ezpExtensionOptions
Definition: ezpextensionoptions.php:59
$result
$result
Definition: companysearch.php:94
$args
$args
Definition: companytypelist.php:125
file_exists
static file_exists( $inifilename)
Definition: eZPBINIFile.php:195
$contents
$contents
Definition: ezarticle/user/extendedsearch.php:52
$file
$file
Definition: ezfilemanager/user/filedownload.php:35
$limit
$limit
Definition: ezimagecatalogue/admin/imagelist.php:312
$ret
$ret
Definition: ezsitemanager/admin/filelist.php:88
$res
$res
Definition: ezstats/admin/cron.php:45
eZClusterEventListener
Definition: ezclustereventlistener.php:15
eZClusterEventNotifier
Definition: ezclustereventnotifier.php:16
eZClusterFileHandlerInterface
Definition: ezclusterfilehandlerinterface.php:16
ezpDatabaseBasedClusterFileHandler
Definition: ezpdatabasebasedclusterfilehandler.php:21
$count
$count
Definition: onlinetypelist.php:108
Copyright © 1998 – 2026 7x. All rights reserved. Licensed under the GNU GPLv2+.