X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=framework%2Fmain%2Fclasses%2Ffile_directories%2Fbinary%2Findex%2Fclass_IndexFile.php;h=bed690ff714585a744464ce231bdf95d7733ae1d;hb=027c5659e968546a21be37e70d700c7e14cba993;hp=f733589640b774f6c0f0b022365d3dff5ac66589;hpb=78a010fef84895720e796842208f01dfb619c332;p=core.git diff --git a/framework/main/classes/file_directories/binary/index/class_IndexFile.php b/framework/main/classes/file_directories/binary/index/class_IndexFile.php index f7335896..bed690ff 100644 --- a/framework/main/classes/file_directories/binary/index/class_IndexFile.php +++ b/framework/main/classes/file_directories/binary/index/class_IndexFile.php @@ -1,13 +1,27 @@ * @version 0.0.0 - * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2023 Core Developer Team * @license GNU GPL 3.0 or any newer version * @link http://www.ship-simu.org * @@ -24,13 +38,13 @@ namespace CoreFramework\Filesystem\Index; * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -class IndexFile extends BaseBinaryFile implements Block { +class IndexFile extends BaseBinaryFile implements IndexableFile { /** * Protected constructor * * @return void */ - protected function __construct () { + private function __construct () { // Call parent constructor parent::__construct(__CLASS__); } @@ -38,49 +52,202 @@ class IndexFile extends BaseBinaryFile implements Block { /** * Creates an instance of this File class and prepares it for usage * - * @param $fileName Name of the index file - * @param $blockInstance An instance of a Block class - * @return $fileInstance An instance of this File class + * @param $fileInfoInstance An instance of a SplFileInfo class + * @param $indexInstance An instance of a Indexable class + * @return $indexFileInstance An instance of an IndexableFile class */ - public final static function createIndexFile ($fileName, Block $blockInstance) { + public final static function createIndexFile (SplFileInfo $fileInfoInstance, Indexable $indexInstance) { // Get a new instance - $fileInstance = new IndexFile(); + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: fileInfoInstance[%s]=%s,indexInstance=%s - CALLED!', get_class($fileInfoInstance), $fileInfoInstance, $indexInstance->__toString())); + $indexFileInstance = new IndexFile(); - // Set block instance here for callbacks - $fileInstance->setBlockInstance($blockInstance); + // Set file instance here for callbacks + $indexFileInstance->setIndexInstance($indexInstance); + + // Expand file name with .idx + $indexInfoInstance = new SplFileInfo(sprintf('%s.idx', $fileInfoInstance->__toString())); // Init this abstract file - $fileInstance->initFile($fileName); + $indexFileInstance->initFile($indexInfoInstance); + + // Init counters and gaps array + $indexFileInstance->initCountersGapsArray(); // Return the prepared instance - return $fileInstance; + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: indexFileInstance=%s - EXIT!', $indexFileInstance->__toString())); + return $indexFileInstance; + } + + /** + * Flushes the file header + * + * @return void + * @throws BadMethodCallException If this->indexInstance is not properly set + */ + public function flushFileHeader () { + // Validate call + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('INDEX-FILE: CALLED!'); + if (!($this->getIndexInstance() instanceof Indexable)) { + // Index instance not set + throw new BadMethodCallException('this->indexInstance[] is not properly set.'); + } + + // Call block instance + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('INDEX-FILE: Invoking this->indexInstance->flushFileHeader() ...'); + $this->getIndexInstance()->flushFileHeader(); + + // Trace message + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('INDEX-FILE: EXIT!'); + } + + /** + * Pre-allocates file (if enabled) with some space for later faster write access. + * + * @param $type Type of the file + * @return void + * @throws InvalidArgumentException If a parameter is empty + * @throws BadMethodCallException If this->indexInstance is not properly set + */ + public function preAllocateFile (string $type) { + // Is it enabled? + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: type=%s - CALLED!', $type)); + if (empty($type)) { + // Empty type + throw new InvalidArgumentException('Parameter "type" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT); + } elseif (!($this->getIndexInstance() instanceof Indexable)) { + // Index instance not set + throw new BadMethodCallException('this->indexInstance[] is not properly set.'); + } + + // Message to user + self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('INDEX-FILE: Pre-allocating file ...'); + + // Calculate minimum block length + $minimumBlockLength = $this->getIndexInstance()->calculateMinimumBlockLength(); + + // Call protected method + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: Invoking this->preAllocateFileByTypeLength(%s,%d) ...', $type, $minimumBlockLength)); + $this->preAllocateFileByTypeLength($type, $minimumBlockLength); + + // Trace message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('INDEX-FILE: EXIT!'); + } + + /** + * Checks wether the current entry is valid (not at the end of the file). + * This method will return true if an emptied (nulled) entry has been found. + * + * @return $isValid Whether the next entry is valid + * @throws UnexpectedValueException If some value is not expected + * @throws BadMethodCallException If this->indexInstance is not properly set + */ + public function isValid () { + // Validate call + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('INDEX-FILE: CALLED!'); + if (!($this->getIndexInstance() instanceof Indexable)) { + // Index instance not set + throw new BadMethodCallException('this->indexInstance[] is not properly set.'); + } + + // Get length from index + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('INDEX-FILE: Invoking this->indexInstance->calculateMinimumBlockLength() ...'); + $length = $this->getIndexInstance()->calculateMinimumBlockLength(); + + // Call protected method + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: Invoking this->isValidByLength(%d) ...', $length)); + $isValid = $this->isValidByLength($length); + + // Return result + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: isValid=%d - EXIT!', intval($isValid))); + return $isValid; + } + + /** + * Reads next "block" of bytes into $currentBlock field. THis method loads + * the whole file into memory when the file is just freshly initialized + * (only zeros in it). + * + * @return void + */ + protected function readNextBlock () { + // First calculate minimum block length + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: this->seekPosition=%d - CALLED!', $this->getSeekPosition())); + $length = $this->getIndexInstance()->calculateMinimumBlockLength(); + + // Call protected method + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: Invoking parent::readNextBlockByLength(%d) ...', $length)); + parent::readNextBlockByLength($length); + + // Trace message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('INDEX-FILE: EXIT!'); + } + + /** + * Reads the file header + * + * @return void + */ + public function readFileHeader () { + // Call index class' method + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('INDEX-FILE: Invoking this->indexInstance->readIndexHeader() - CALLED!'); + $this->getIndexInstance()->readIndexHeader(); + + // Trace message + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('INDEX-FILE: EXIT!'); } /** * Writes given value to the file and returns a hash and gap position for it * - * @param $groupId Group identifier + * @param $stackName Group identifier * @param $value Value to be added to the stack * @return $data Hash and gap position - * @throws UnsupportedOperationException If this method is called + * @throws InvalidArgumentException If a parameter is not valid + * @throws BadMethodCallException If this->indexInstance is not properly set */ - public function writeValueToFile ($groupId, $value) { - self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] groupId=' . $groupId . ',value[' . gettype($value) . ']=' . print_r($value, TRUE)); - throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION); + public function writeValueToFile (string $stackName, $value) { + // Validate parameter + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: stackName=%s,value[]=%s - CALLED!', $stackName, gettype($value))); + if (empty($stackName)) { + // Throw IAE + throw new InvalidArgumentException('Parameter "stackName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT); + } elseif (is_object($value) || is_resource($value)) { + // Not wanted here + throw new InvalidArgumentException(sprintf('value[]=%s is not stackable in files', gettype($value))); + } elseif (!($this->getIndexInstance() instanceof Indexable)) { + // Index instance not set + throw new BadMethodCallException('this->indexInstance[] is not properly set.'); + } + + // Encode/convert the value into a "binary format" + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: Invoking StringUtils::encodeData(value[]=%s) ...', gettype($value))); + $encoded = StringUtils::encodeData($value); + + // Get a strong hash for the "encoded" data + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: encoded(%d)=%s', strlen($encoded), $encoded)); + $hash = CryptoUtils::hash($encoded); + + // Then write it to the next free gap + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: hash=%s', $hash)); + $data = $this->getIndexInstance()->writeDataToFreeGap($stackName, $hash, $encoded); + + // Return info + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('INDEX-FILE: data[]=%s - EXIT!', gettype($data))); + return $data; } /** * Writes given raw data to the file and returns a gap position and length * - * @param $groupId Group identifier + * @param $stackName Group identifier * @param $hash Hash from encoded value * @param $encoded Encoded value to be written to the file * @return $data Gap position and length of the raw data * @throws UnsupportedOperationException If this method is called */ - public function writeDataToFreeGap ($groupId, $hash, $encoded) { - self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] groupId=' . $groupId . ',encoded()=' . strlen($encoded)); - throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION); + public function writeDataToFreeGap (string $stackName, string $hash, string $encoded) { + self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('INDEX-FILE: stackName=' . $stackName . ',hash=' . $hash . ',encoded()=' . strlen($encoded)); + throw new UnsupportedOperationException([$this, __FUNCTION__], FrameworkInterface::EXCEPTION_UNSPPORTED_OPERATION); } }