Source of file Writer.php
Size: 33,665 Bytes - Last Modified: 2021-12-23T10:29:30+00:00
/var/www/docs.ssmods.com/process/src/thirdparty/Zend/Search/Lucene/Index/Writer.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864 | <?php /** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category Zend * @package Zend_Search_Lucene * @subpackage Index * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @version $Id: Writer.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * Zend_Search_Lucene_LockManager */ require_once 'Zend/Search/Lucene/LockManager.php'; /** * @category Zend * @package Zend_Search_Lucene * @subpackage Index * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Search_Lucene_Index_Writer { /** * @todo Implement Analyzer substitution * @todo Implement Zend_Search_Lucene_Storage_DirectoryRAM and Zend_Search_Lucene_Storage_FileRAM to use it for * temporary index files * @todo Directory lock processing */ /** * Number of documents required before the buffered in-memory * documents are written into a new Segment * * Default value is 10 * * @var integer */ public $maxBufferedDocs = 10; /** * Largest number of documents ever merged by addDocument(). * Small values (e.g., less than 10,000) are best for interactive indexing, * as this limits the length of pauses while indexing to a few seconds. * Larger values are best for batched indexing and speedier searches. * * Default value is PHP_INT_MAX * * @var integer */ public $maxMergeDocs = PHP_INT_MAX; /** * Determines how often segment indices are merged by addDocument(). * * With smaller values, less RAM is used while indexing, * and searches on unoptimized indices are faster, * but indexing speed is slower. * * With larger values, more RAM is used during indexing, * and while searches on unoptimized indices are slower, * indexing is faster. * * Thus larger values (> 10) are best for batch index creation, * and smaller values (< 10) for indices that are interactively maintained. * * Default value is 10 * * @var integer */ public $mergeFactor = 10; /** * File system adapter. * * @var Zend_Search_Lucene_Storage_Directory */ private $_directory = null; /** * Changes counter. * * @var integer */ private $_versionUpdate = 0; /** * List of the segments, created by index writer * Array of Zend_Search_Lucene_Index_SegmentInfo objects * * @var array */ private $_newSegments = array(); /** * List of segments to be deleted on commit * * @var array */ private $_segmentsToDelete = array(); /** * Current segment to add documents * * @var Zend_Search_Lucene_Index_SegmentWriter_DocumentWriter */ private $_currentSegment = null; /** * Array of Zend_Search_Lucene_Index_SegmentInfo objects for this index. * * It's a reference to the corresponding Zend_Search_Lucene::$_segmentInfos array * * @var array Zend_Search_Lucene_Index_SegmentInfo */ private $_segmentInfos; /** * Index target format version * * @var integer */ private $_targetFormatVersion; /** * List of indexfiles extensions * * @var array */ private static $_indexExtensions = array('.cfs' => '.cfs', '.cfx' => '.cfx', '.fnm' => '.fnm', '.fdx' => '.fdx', '.fdt' => '.fdt', '.tis' => '.tis', '.tii' => '.tii', '.frq' => '.frq', '.prx' => '.prx', '.tvx' => '.tvx', '.tvd' => '.tvd', '.tvf' => '.tvf', '.del' => '.del', '.sti' => '.sti' ); /** * Create empty index * * @param Zend_Search_Lucene_Storage_Directory $directory * @param integer $generation * @param integer $nameCount */ public static function createIndex(Zend_Search_Lucene_Storage_Directory $directory, $generation, $nameCount) { if ($generation == 0) { // Create index in pre-2.1 mode foreach ($directory->fileList() as $file) { if ($file == 'deletable' || $file == 'segments' || isset(self::$_indexExtensions[ substr($file, strlen($file)-4)]) || preg_match('/\.f\d+$/i', $file) /* matches <segment_name>.f<decimal_nmber> file names */ ) { $directory->deleteFile($file); } } $segmentsFile = $directory->createFile('segments'); $segmentsFile->writeInt((int)0xFFFFFFFF); // write version (initialized by current time) $segmentsFile->writeLong(round(microtime(true))); // write name counter $segmentsFile->writeInt($nameCount); // write segment counter $segmentsFile->writeInt(0); $deletableFile = $directory->createFile('deletable'); // write counter $deletableFile->writeInt(0); } else { $genFile = $directory->createFile('segments.gen'); $genFile->writeInt((int)0xFFFFFFFE); // Write generation two times $genFile->writeLong($generation); $genFile->writeLong($generation); $segmentsFile = $directory->createFile(Zend_Search_Lucene::getSegmentFileName($generation)); $segmentsFile->writeInt((int)0xFFFFFFFD); // write version (initialized by current time) $segmentsFile->writeLong(round(microtime(true))); // write name counter $segmentsFile->writeInt($nameCount); // write segment counter $segmentsFile->writeInt(0); } } /** * Open the index for writing * * @param Zend_Search_Lucene_Storage_Directory $directory * @param array $segmentInfos * @param integer $targetFormatVersion * @param Zend_Search_Lucene_Storage_File $cleanUpLock */ public function __construct(Zend_Search_Lucene_Storage_Directory $directory, &$segmentInfos, $targetFormatVersion) { $this->_directory = $directory; $this->_segmentInfos = &$segmentInfos; $this->_targetFormatVersion = $targetFormatVersion; } /** * Adds a document to this index. * * @param Zend_Search_Lucene_Document $document */ public function addDocument(Zend_Search_Lucene_Document $document) { /** * Zend_Search_Lucene_Index_SegmentWriter_DocumentWriter */ include_once 'Zend/Search/Lucene/Index/SegmentWriter/DocumentWriter.php'; if ($this->_currentSegment === null) { $this->_currentSegment = new Zend_Search_Lucene_Index_SegmentWriter_DocumentWriter($this->_directory, $this->_newSegmentName()); } $this->_currentSegment->addDocument($document); if ($this->_currentSegment->count() >= $this->maxBufferedDocs) { $this->commit(); } $this->_maybeMergeSegments(); $this->_versionUpdate++; } /** * Check if we have anything to merge * * @return boolean */ private function _hasAnythingToMerge() { $segmentSizes = array(); foreach ($this->_segmentInfos as $segName => $segmentInfo) { $segmentSizes[$segName] = $segmentInfo->count(); } $mergePool = array(); $poolSize = 0; $sizeToMerge = $this->maxBufferedDocs; asort($segmentSizes, SORT_NUMERIC); foreach ($segmentSizes as $segName => $size) { // Check, if segment comes into a new merging block while ($size >= $sizeToMerge) { // Merge previous block if it's large enough if ($poolSize >= $sizeToMerge) { return true; } $mergePool = array(); $poolSize = 0; $sizeToMerge *= $this->mergeFactor; if ($sizeToMerge > $this->maxMergeDocs) { return false; } } $mergePool[] = $this->_segmentInfos[$segName]; $poolSize += $size; } if ($poolSize >= $sizeToMerge) { return true; } return false; } /** * Merge segments if necessary */ private function _maybeMergeSegments() { if (Zend_Search_Lucene_LockManager::obtainOptimizationLock($this->_directory) === false) { return; } if (!$this->_hasAnythingToMerge()) { Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); return; } // Update segments list to be sure all segments are not merged yet by another process // // Segment merging functionality is concentrated in this class and surrounded // by optimization lock obtaining/releasing. // _updateSegments() refreshes segments list from the latest index generation. // So only new segments can be added to the index while we are merging some already existing // segments. // Newly added segments will be also included into the index by the _updateSegments() call // either by another process or by the current process with the commit() call at the end of _mergeSegments() method. // That's guaranteed by the serialisation of _updateSegments() execution using exclusive locks. $this->_updateSegments(); // Perform standard auto-optimization procedure $segmentSizes = array(); foreach ($this->_segmentInfos as $segName => $segmentInfo) { $segmentSizes[$segName] = $segmentInfo->count(); } $mergePool = array(); $poolSize = 0; $sizeToMerge = $this->maxBufferedDocs; asort($segmentSizes, SORT_NUMERIC); foreach ($segmentSizes as $segName => $size) { // Check, if segment comes into a new merging block while ($size >= $sizeToMerge) { // Merge previous block if it's large enough if ($poolSize >= $sizeToMerge) { $this->_mergeSegments($mergePool); } $mergePool = array(); $poolSize = 0; $sizeToMerge *= $this->mergeFactor; if ($sizeToMerge > $this->maxMergeDocs) { Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); return; } } $mergePool[] = $this->_segmentInfos[$segName]; $poolSize += $size; } if ($poolSize >= $sizeToMerge) { $this->_mergeSegments($mergePool); } Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); } /** * Merge specified segments * * $segments is an array of SegmentInfo objects * * @param array $segments */ private function _mergeSegments($segments) { $newName = $this->_newSegmentName(); /** * Zend_Search_Lucene_Index_SegmentMerger */ include_once 'Zend/Search/Lucene/Index/SegmentMerger.php'; $merger = new Zend_Search_Lucene_Index_SegmentMerger( $this->_directory, $newName ); foreach ($segments as $segmentInfo) { $merger->addSource($segmentInfo); $this->_segmentsToDelete[$segmentInfo->getName()] = $segmentInfo->getName(); } $newSegment = $merger->merge(); if ($newSegment !== null) { $this->_newSegments[$newSegment->getName()] = $newSegment; } $this->commit(); } /** * Update segments file by adding current segment to a list * * @throws Zend_Search_Lucene_Exception */ private function _updateSegments() { // Get an exclusive index lock Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory); // Write down changes for the segments foreach ($this->_segmentInfos as $segInfo) { $segInfo->writeChanges(); } $generation = Zend_Search_Lucene::getActualGeneration($this->_directory); $segmentsFile = $this->_directory->getFileObject(Zend_Search_Lucene::getSegmentFileName($generation), false); $newSegmentFile = $this->_directory->createFile(Zend_Search_Lucene::getSegmentFileName(++$generation), false); try { $genFile = $this->_directory->getFileObject('segments.gen', false); } catch (Zend_Search_Lucene_Exception $e) { if (strpos($e->getMessage(), 'is not readable') !== false) { $genFile = $this->_directory->createFile('segments.gen'); } else { throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } } $genFile->writeInt((int)0xFFFFFFFE); // Write generation (first copy) $genFile->writeLong($generation); try { // Write format marker if ($this->_targetFormatVersion == Zend_Search_Lucene::FORMAT_2_1) { $newSegmentFile->writeInt((int)0xFFFFFFFD); } else if ($this->_targetFormatVersion == Zend_Search_Lucene::FORMAT_2_3) { $newSegmentFile->writeInt((int)0xFFFFFFFC); } // Read src file format identifier $format = $segmentsFile->readInt(); if ($format == (int)0xFFFFFFFF) { $srcFormat = Zend_Search_Lucene::FORMAT_PRE_2_1; } else if ($format == (int)0xFFFFFFFD) { $srcFormat = Zend_Search_Lucene::FORMAT_2_1; } else if ($format == (int)0xFFFFFFFC) { $srcFormat = Zend_Search_Lucene::FORMAT_2_3; } else { throw new Zend_Search_Lucene_Exception('Unsupported segments file format'); } $version = $segmentsFile->readLong() + $this->_versionUpdate; $this->_versionUpdate = 0; $newSegmentFile->writeLong($version); // Write segment name counter $newSegmentFile->writeInt($segmentsFile->readInt()); // Get number of segments offset $numOfSegmentsOffset = $newSegmentFile->tell(); // Write dummy data (segment counter) $newSegmentFile->writeInt(0); // Read number of segemnts $segmentsCount = $segmentsFile->readInt(); $segments = array(); for ($count = 0; $count < $segmentsCount; $count++) { $segName = $segmentsFile->readString(); $segSize = $segmentsFile->readInt(); if ($srcFormat == Zend_Search_Lucene::FORMAT_PRE_2_1) { // pre-2.1 index format $delGen = 0; $hasSingleNormFile = false; $numField = (int)0xFFFFFFFF; $isCompoundByte = 0; $docStoreOptions = null; } else { $delGen = $segmentsFile->readLong(); if ($srcFormat == Zend_Search_Lucene::FORMAT_2_3) { $docStoreOffset = $segmentsFile->readInt(); if ($docStoreOffset != (int)0xFFFFFFFF) { $docStoreSegment = $segmentsFile->readString(); $docStoreIsCompoundFile = $segmentsFile->readByte(); $docStoreOptions = array('offset' => $docStoreOffset, 'segment' => $docStoreSegment, 'isCompound' => ($docStoreIsCompoundFile == 1)); } else { $docStoreOptions = null; } } else { $docStoreOptions = null; } $hasSingleNormFile = $segmentsFile->readByte(); $numField = $segmentsFile->readInt(); $normGens = array(); if ($numField != (int)0xFFFFFFFF) { for ($count1 = 0; $count1 < $numField; $count1++) { $normGens[] = $segmentsFile->readLong(); } } $isCompoundByte = $segmentsFile->readByte(); } if (!in_array($segName, $this->_segmentsToDelete)) { // Load segment if necessary if (!isset($this->_segmentInfos[$segName])) { if ($isCompoundByte == 0xFF) { // The segment is not a compound file $isCompound = false; } else if ($isCompoundByte == 0x00) { // The status is unknown $isCompound = null; } else if ($isCompoundByte == 0x01) { // The segment is a compound file $isCompound = true; } /** * Zend_Search_Lucene_Index_SegmentInfo */ include_once 'Zend/Search/Lucene/Index/SegmentInfo.php'; $this->_segmentInfos[$segName] = new Zend_Search_Lucene_Index_SegmentInfo( $this->_directory, $segName, $segSize, $delGen, $docStoreOptions, $hasSingleNormFile, $isCompound ); } else { // Retrieve actual deletions file generation number $delGen = $this->_segmentInfos[$segName]->getDelGen(); } $newSegmentFile->writeString($segName); $newSegmentFile->writeInt($segSize); $newSegmentFile->writeLong($delGen); if ($this->_targetFormatVersion == Zend_Search_Lucene::FORMAT_2_3) { if ($docStoreOptions !== null) { $newSegmentFile->writeInt($docStoreOffset); $newSegmentFile->writeString($docStoreSegment); $newSegmentFile->writeByte($docStoreIsCompoundFile); } else { // Set DocStoreOffset to -1 $newSegmentFile->writeInt((int)0xFFFFFFFF); } } else if ($docStoreOptions !== null) { // Release index write lock Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); throw new Zend_Search_Lucene_Exception('Index conversion to lower format version is not supported.'); } $newSegmentFile->writeByte($hasSingleNormFile); $newSegmentFile->writeInt($numField); if ($numField != (int)0xFFFFFFFF) { foreach ($normGens as $normGen) { $newSegmentFile->writeLong($normGen); } } $newSegmentFile->writeByte($isCompoundByte); $segments[$segName] = $segSize; } } $segmentsFile->close(); $segmentsCount = count($segments) + count($this->_newSegments); foreach ($this->_newSegments as $segName => $segmentInfo) { $newSegmentFile->writeString($segName); $newSegmentFile->writeInt($segmentInfo->count()); // delete file generation: -1 (there is no delete file yet) $newSegmentFile->writeInt((int)0xFFFFFFFF);$newSegmentFile->writeInt((int)0xFFFFFFFF); if ($this->_targetFormatVersion == Zend_Search_Lucene::FORMAT_2_3) { // docStoreOffset: -1 (segment doesn't use shared doc store) $newSegmentFile->writeInt((int)0xFFFFFFFF); } // HasSingleNormFile $newSegmentFile->writeByte($segmentInfo->hasSingleNormFile()); // NumField $newSegmentFile->writeInt((int)0xFFFFFFFF); // IsCompoundFile $newSegmentFile->writeByte($segmentInfo->isCompound() ? 1 : -1); $segments[$segmentInfo->getName()] = $segmentInfo->count(); $this->_segmentInfos[$segName] = $segmentInfo; } $this->_newSegments = array(); $newSegmentFile->seek($numOfSegmentsOffset); $newSegmentFile->writeInt($segmentsCount); // Update segments count $newSegmentFile->close(); } catch (Exception $e) { /** * Restore previous index generation */ $generation--; $genFile->seek(4, SEEK_SET); // Write generation number twice $genFile->writeLong($generation); $genFile->writeLong($generation); // Release index write lock Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); // Throw the exception include_once 'Zend/Search/Lucene/Exception.php'; throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } // Write generation (second copy) $genFile->writeLong($generation); // Check if another update or read process is not running now // If yes, skip clean-up procedure if (Zend_Search_Lucene_LockManager::escalateReadLock($this->_directory)) { /** * Clean-up directory */ $filesToDelete = array(); $filesTypes = array(); $filesNumbers = array(); // list of .del files of currently used segments // each segment can have several generations of .del files // only last should not be deleted $delFiles = array(); foreach ($this->_directory->fileList() as $file) { if ($file == 'deletable') { // 'deletable' file $filesToDelete[] = $file; $filesTypes[] = 0; // delete this file first, since it's not used starting from Lucene v2.1 $filesNumbers[] = 0; } else if ($file == 'segments') { // 'segments' file $filesToDelete[] = $file; $filesTypes[] = 1; // second file to be deleted "zero" version of segments file (Lucene pre-2.1) $filesNumbers[] = 0; } else if (preg_match('/^segments_[a-zA-Z0-9]+$/i', $file)) { // 'segments_xxx' file // Check if it's not a just created generation file if ($file != Zend_Search_Lucene::getSegmentFileName($generation)) { $filesToDelete[] = $file; $filesTypes[] = 2; // first group of files for deletions $filesNumbers[] = (int)base_convert(substr($file, 9), 36, 10); // ordered by segment generation numbers } } else if (preg_match('/(^_([a-zA-Z0-9]+))\.f\d+$/i', $file, $matches)) { // one of per segment files ('<segment_name>.f<decimal_number>') // Check if it's not one of the segments in the current segments set if (!isset($segments[$matches[1]])) { $filesToDelete[] = $file; $filesTypes[] = 3; // second group of files for deletions $filesNumbers[] = (int)base_convert($matches[2], 36, 10); // order by segment number } } else if (preg_match('/(^_([a-zA-Z0-9]+))(_([a-zA-Z0-9]+))\.del$/i', $file, $matches)) { // one of per segment files ('<segment_name>_<del_generation>.del' where <segment_name> is '_<segment_number>') // Check if it's not one of the segments in the current segments set if (!isset($segments[$matches[1]])) { $filesToDelete[] = $file; $filesTypes[] = 3; // second group of files for deletions $filesNumbers[] = (int)base_convert($matches[2], 36, 10); // order by segment number } else { $segmentNumber = (int)base_convert($matches[2], 36, 10); $delGeneration = (int)base_convert($matches[4], 36, 10); if (!isset($delFiles[$segmentNumber])) { $delFiles[$segmentNumber] = array(); } $delFiles[$segmentNumber][$delGeneration] = $file; } } else if (isset(self::$_indexExtensions[substr($file, strlen($file)-4)])) { // one of per segment files ('<segment_name>.<ext>') $segmentName = substr($file, 0, strlen($file) - 4); // Check if it's not one of the segments in the current segments set if (!isset($segments[$segmentName]) && ($this->_currentSegment === null || $this->_currentSegment->getName() != $segmentName) ) { $filesToDelete[] = $file; $filesTypes[] = 3; // second group of files for deletions $filesNumbers[] = (int)base_convert(substr($file, 1 /* skip '_' */, strlen($file)-5), 36, 10); // order by segment number } } } $maxGenNumber = 0; // process .del files of currently used segments foreach ($delFiles as $segmentNumber => $segmentDelFiles) { ksort($delFiles[$segmentNumber], SORT_NUMERIC); array_pop($delFiles[$segmentNumber]); // remove last delete file generation from candidates for deleting end($delFiles[$segmentNumber]); $lastGenNumber = key($delFiles[$segmentNumber]); if ($lastGenNumber > $maxGenNumber) { $maxGenNumber = $lastGenNumber; } } foreach ($delFiles as $segmentNumber => $segmentDelFiles) { foreach ($segmentDelFiles as $delGeneration => $file) { $filesToDelete[] = $file; $filesTypes[] = 4; // third group of files for deletions $filesNumbers[] = $segmentNumber*$maxGenNumber + $delGeneration; // order by <segment_number>,<del_generation> pair } } // Reorder files for deleting array_multisort( $filesTypes, SORT_ASC, SORT_NUMERIC, $filesNumbers, SORT_ASC, SORT_NUMERIC, $filesToDelete, SORT_ASC, SORT_STRING ); foreach ($filesToDelete as $file) { try { /** * Skip shared docstore segments deleting */ /** * @todo Process '.cfx' files to check if them are already unused */ if (substr($file, strlen($file)-4) != '.cfx') { $this->_directory->deleteFile($file); } } catch (Zend_Search_Lucene_Exception $e) { if (strpos($e->getMessage(), 'Can\'t delete file') === false) { // That's not "file is under processing or already deleted" exception // Pass it through throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } } } // Return read lock into the previous state Zend_Search_Lucene_LockManager::deEscalateReadLock($this->_directory); } else { // Only release resources if another index reader is running now foreach ($this->_segmentsToDelete as $segName) { foreach (self::$_indexExtensions as $ext) { $this->_directory->purgeFile($segName . $ext); } } } // Clean-up _segmentsToDelete container $this->_segmentsToDelete = array(); // Release index write lock Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); // Remove unused segments from segments list foreach ($this->_segmentInfos as $segName => $segmentInfo) { if (!isset($segments[$segName])) { unset($this->_segmentInfos[$segName]); } } } /** * Commit current changes */ public function commit() { if ($this->_currentSegment !== null) { $newSegment = $this->_currentSegment->close(); if ($newSegment !== null) { $this->_newSegments[$newSegment->getName()] = $newSegment; } $this->_currentSegment = null; } $this->_updateSegments(); } /** * Merges the provided indexes into this index. * * @param array $readers * @return void */ public function addIndexes($readers) { /** * @todo implementation */ } /** * Merges all segments together into new one * * Returns true on success and false if another optimization or auto-optimization process * is running now * * @return boolean */ public function optimize() { if (Zend_Search_Lucene_LockManager::obtainOptimizationLock($this->_directory) === false) { return false; } // Update segments list to be sure all segments are not merged yet by another process // // Segment merging functionality is concentrated in this class and surrounded // by optimization lock obtaining/releasing. // _updateSegments() refreshes segments list from the latest index generation. // So only new segments can be added to the index while we are merging some already existing // segments. // Newly added segments will be also included into the index by the _updateSegments() call // either by another process or by the current process with the commit() call at the end of _mergeSegments() method. // That's guaranteed by the serialisation of _updateSegments() execution using exclusive locks. $this->_updateSegments(); $this->_mergeSegments($this->_segmentInfos); Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); return true; } /** * Get name for new segment * * @return string */ private function _newSegmentName() { Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory); $generation = Zend_Search_Lucene::getActualGeneration($this->_directory); $segmentsFile = $this->_directory->getFileObject(Zend_Search_Lucene::getSegmentFileName($generation), false); $segmentsFile->seek(12); // 12 = 4 (int, file format marker) + 8 (long, index version) $segmentNameCounter = $segmentsFile->readInt(); $segmentsFile->seek(12); // 12 = 4 (int, file format marker) + 8 (long, index version) $segmentsFile->writeInt($segmentNameCounter + 1); // Flash output to guarantee that wrong value will not be loaded between unlock and // return (which calls $segmentsFile destructor) $segmentsFile->flush(); Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); return '_' . base_convert($segmentNameCounter, 10, 36); } } |