📄 writer.php
字号:
$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); $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 $e; } } $genFile->writeInt((int)0xFFFFFFFE); // Write generation (first copy) $genFile->writeLong($generation);
try { // Write format marker $newSegmentFile->writeInt((int)0xFFFFFFFD); // Skip format identifier $segmentsFile->seek(4, SEEK_CUR); // $version = $segmentsFile->readLong() + $this->_versionUpdate; // Process version on 32-bit platforms $versionHigh = $segmentsFile->readInt(); $versionLow = $segmentsFile->readInt(); $version = $versionHigh * ((double)0xFFFFFFFF + 1) + (($versionLow < 0)? (double)0xFFFFFFFF - (-1 - $versionLow) : $versionLow); $version += $this->_versionUpdate; $this->_versionUpdate = 0; $newSegmentFile->writeInt((int)($version/((double)0xFFFFFFFF + 1))); $newSegmentFile->writeInt((int)($version & 0xFFFFFFFF)); // 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 ($generation == 1 /* retrieved generation is 0 */) { // pre-2.1 index format $delGenHigh = 0; $delGenLow = 0; $hasSingleNormFile = false; $numField = (int)0xFFFFFFFF; $isCompound = 1; } else { //$delGen = $segmentsFile->readLong(); $delGenHigh = $segmentsFile->readInt(); $delGenLow = $segmentsFile->readInt(); $hasSingleNormFile = $segmentsFile->readByte(); $numField = $segmentsFile->readInt(); $normGens = array(); if ($numField != (int)0xFFFFFFFF) { for ($count1 = 0; $count1 < $numField; $count1++) { $normGens[] = $segmentsFile->readLong(); } } $isCompound = $segmentsFile->readByte(); } if (!in_array($segName, $this->_segmentsToDelete)) { // Load segment if necessary if (!isset($this->_segmentInfos[$segName])) { $delGen = $delGenHigh * ((double)0xFFFFFFFF + 1) + (($delGenLow < 0)? (double)0xFFFFFFFF - (-1 - $delGenLow) : $delGenLow); $this->_segmentInfos[$segName] = new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, $segName, $segSize, $delGen, $hasSingleNormFile, $isCompound); } else { // Retrieve actual detetions file generation number $delGen = $this->_segmentInfos[$segName]->getDelGen(); if ($delGen >= 0) { $delGenHigh = (int)($delGen/((double)0xFFFFFFFF + 1)); $delGenLow =(int)($delGen & 0xFFFFFFFF); } else { $delGenHigh = $delGenLow = (int)0xFFFFFFFF; } } $newSegmentFile->writeString($segName); $newSegmentFile->writeInt($segSize); $newSegmentFile->writeInt($delGenHigh); $newSegmentFile->writeInt($delGenLow); $newSegmentFile->writeByte($hasSingleNormFile); $newSegmentFile->writeInt($numField); if ($numField != (int)0xFFFFFFFF) { foreach ($normGens as $normGen) { $newSegmentFile->writeLong($normGen); } } $newSegmentFile->writeByte($isCompound); $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); // HasSingleNormFile $newSegmentFile->writeByte($segmentInfo->hasSingleNormFile()); // NumField $newSegmentFile->writeInt((int)0xFFFFFFFF); // IsCompoundFile $newSegmentFile->writeByte($segmentInfo->isCompound()); $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
throw $e;
} // Write generation (second copy) $genFile->writeLong($generation);
// Check if another update 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 {
$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 $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;
}
$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); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -