X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=framework%2Fmain%2Fclasses%2Fstacker%2Ffile%2Fclass_BaseFileStack.php;h=30f20f9c93fcc9c39e8564bfc6844155d979e65c;hb=6e91754d589773df8bd3746008dd782133a48674;hp=be93645864e2039753178daf1ba6a36016b7824b;hpb=4f9cf34b521892cb99fae9b21b92787f3d555b74;p=core.git diff --git a/framework/main/classes/stacker/file/class_BaseFileStack.php b/framework/main/classes/stacker/file/class_BaseFileStack.php index be936458..30f20f9c 100644 --- a/framework/main/classes/stacker/file/class_BaseFileStack.php +++ b/framework/main/classes/stacker/file/class_BaseFileStack.php @@ -1,20 +1,31 @@ * @version 0.0.0 - * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2020 Core Developer Team * @license GNU GPL 3.0 or any newer version * @link http://www.ship-simu.org * @@ -31,26 +42,18 @@ use Org\Mxchange\CoreFramework\Stacker\BaseStacker; * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -class BaseFileStack extends BaseStacker { - /** - * Magic for this stack - */ - const STACK_MAGIC = 'STACKv0.1'; - - /** - * Name of array index for gap position - */ - const ARRAY_INDEX_GAP_POSITION = 'gap'; +abstract class BaseFileStack extends BaseStacker implements StackableFile { + // Load traits + use IndexableTrait; + use IteratorTrait; - /** - * Name of array index for hash - */ - const ARRAY_INDEX_HASH = 'hash'; + // Exception codes + const EXCEPTION_BAD_MAGIC = 0xe100; /** - * Name of array index for length of raw data + * Minimum block length */ - const ARRAY_INDEX_DATA_LENGTH = 'length'; + private static $minimumBlockLength = 0; /** * Protected constructor @@ -58,7 +61,7 @@ class BaseFileStack extends BaseStacker { * @param $className Name of the class * @return void */ - protected function __construct ($className) { + protected function __construct (string $className) { // Call parent constructor parent::__construct($className); } @@ -68,25 +71,37 @@ class BaseFileStack extends BaseStacker { * * @return void * @todo To hard assertions here, better rewrite them to exceptions + * @throws UnexpectedValueException If header is not proper length + * @throws InvalidMagicException If a bad magic was found */ public function readFileHeader () { - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__)); - // First rewind to beginning as the header sits at the beginning ... + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FILE-STACK: CALLED!'); $this->getIteratorInstance()->rewind(); // Then read it (see constructor for calculation) $data = $this->getIteratorInstance()->read($this->getIteratorInstance()->getHeaderSize()); - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Read %d bytes (%d wanted).', __METHOD__, __LINE__, strlen($data), $this->getIteratorInstance()->getHeaderSize())); + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: Read %d bytes (%d wanted).', strlen($data), $this->getIteratorInstance()->getHeaderSize())); // Have all requested bytes been read? - assert(strlen($data) == $this->getIteratorInstance()->getHeaderSize()); - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__)); + if (strlen($data) != $this->getIteratorInstance()->getHeaderSize()) { + // Bad data length + throw new UnexpectedValueException(sprintf('data(%d)=%s does not match iteratorInstance->headerSize=%d', + strlen($data), + $data, + $this->getIteratorInstance()->getHeaderSize() + )); + } // Last character must be the separator - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] data(-1)=%s', __METHOD__, __LINE__, dechex(ord(substr($data, -1, 1))))); - assert(substr($data, -1, 1) == chr(BaseBinaryFile::SEPARATOR_HEADER_ENTRIES)); - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__)); + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: data(-1)=%s', dechex(ord(substr($data, -1, 1))))); + if (substr($data, -1, 1) !== chr(BaseBinaryFile::SEPARATOR_HEADER_ENTRIES)) { + // Not valid separator + throw new UnexpectedValueException(sprintf('data=%s does not have separator=%s at the end.', + $data, + BaseBinaryFile::SEPARATOR_HEADER_ENTRIES + )); + } // Okay, then remove it $data = substr($data, 0, -1); @@ -103,29 +118,45 @@ class BaseFileStack extends BaseStacker { */ $header = explode(chr(BaseBinaryFile::SEPARATOR_HEADER_DATA), $data); - // Set header here - $this->getIteratorInstance()->setHeader($header); - // Check if the array has only 3 elements - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] header(%d)=%s', __METHOD__, __LINE__, count($header), print_r($header, true))); - assert(count($header) == 3); - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__)); - - // Check magic - assert($header[0] == self::STACK_MAGIC); - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__)); + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: header(%d)=%s', count($header), print_r($header, true))); + if (count($header) != 3) { + // Header array count is not expected + throw new UnexpectedValueException(sprintf('data=%s has %d elements, expected 3', + $data, + count($header) + )); + } elseif ($header[0] != StackableFile::STACK_MAGIC) { + // Bad magic + throw new InvalidMagicException($data, self::EXCEPTION_BAD_MAGIC); + } // Check length of count and seek position - assert(strlen($header[1]) == BaseBinaryFile::LENGTH_COUNT); - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__)); - assert(strlen($header[2]) == BaseBinaryFile::LENGTH_POSITION); - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__)); + if (strlen($header[1]) != BaseBinaryFile::LENGTH_COUNT) { + // Count length not valid + throw new UnexpectedValueException(sprintf('header[1](%d)=%s is not expected %d length', + strlen($header[1]), + $header[1], + BaseBinaryFile::LENGTH_COUNT + )); + } elseif (strlen($header[1]) != BaseBinaryFile::LENGTH_POSITION) { + // Position length not valid + throw new UnexpectedValueException(sprintf('header[2](%d)=%s is not expected %d length', + strlen($header[1]), + $header[1], + BaseBinaryFile::LENGTH_POSITION + )); + } // Decode count and seek position $header[1] = hex2bin($header[1]); $header[2] = hex2bin($header[2]); - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__)); + // Set header here + $this->getIteratorInstance()->setHeader($header); + + // Trace message + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: EXIT!', __METHOD__, __LINE__)); } /** @@ -134,24 +165,23 @@ class BaseFileStack extends BaseStacker { * @return void */ public function flushFileHeader () { - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__)); - // Put all informations together + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FILE-STACK: CALLED!'); $header = sprintf('%s%s%s%s%s%s', // Magic - self::STACK_MAGIC, + StackableFile::STACK_MAGIC, // Separator magic<->count chr(BaseBinaryFile::SEPARATOR_HEADER_DATA), // Total entries (will be zero) and pad it to 20 chars - str_pad($this->dec2hex($this->getIteratorInstance()->getCounter()), BaseBinaryFile::LENGTH_COUNT, '0', STR_PAD_LEFT), + str_pad(StringUtils::dec2hex($this->getIteratorInstance()->getCounter()), BaseBinaryFile::LENGTH_COUNT, '0', STR_PAD_LEFT), // Separator count<->seek position chr(BaseBinaryFile::SEPARATOR_HEADER_DATA), // Position (will be zero) - str_pad($this->dec2hex($this->getIteratorInstance()->getSeekPosition(), 2), BaseBinaryFile::LENGTH_POSITION, '0', STR_PAD_LEFT), + str_pad(StringUtils::dec2hex($this->getIteratorInstance()->getSeekPosition(), 2), BaseBinaryFile::LENGTH_POSITION, '0', STR_PAD_LEFT), // Separator position<->entries chr(BaseBinaryFile::SEPARATOR_HEADER_ENTRIES) @@ -160,33 +190,39 @@ class BaseFileStack extends BaseStacker { // Write it to disk (header is always at seek position 0) $this->getIteratorInstance()->writeData(0, $header, false); - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__)); + // Trace message + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FILE-STACK: EXIT!'); } /** * Initializes this file-based stack. * - * @param $fileName File name of this stack + * @param $fileInfoInstance An instance of a SplFileInfo class * @param $type Type of this stack (e.g. url_source for URL sources) * @return void + * @throws InvalidArgumentException If a parameter is invalid * @todo Currently the stack file is not cached, please implement a memory-handling class and if enough RAM is found, cache the whole stack file. */ - protected function initFileStack ($fileName, $type) { + protected function initFileStack (SplFileInfo $fileInfoInstance, string $type) { + // Validate parameter + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: fileInfoInstance[%s]=%s,type=%s - CALLED!', get_class($fileInfoInstance), $fileInfoInstance, $type)); + if (empty($type)) { + // Invalid parameter + throw new InvalidArgumentException('Parameter "type" is empty'); + } + // Get a stack file instance - $fileInstance = ObjectFactory::createObjectByConfiguredName('stack_file_class', array($fileName, $this)); + $stackInstance = ObjectFactory::createObjectByConfiguredName('stack_file_class', array($fileInfoInstance, $this)); // Get iterator instance - $iteratorInstance = ObjectFactory::createObjectByConfiguredName('file_iterator_class', array($fileInstance)); - - // Is the instance implementing the right interface? - assert($iteratorInstance instanceof SeekableWritableFileIterator); + $iteratorInstance = ObjectFactory::createObjectByConfiguredName('file_iterator_class', array($stackInstance)); // Set iterator here $this->setIteratorInstance($iteratorInstance); // Calculate header size $this->getIteratorInstance()->setHeaderSize( - strlen(self::STACK_MAGIC) + + strlen(StackableFile::STACK_MAGIC) + strlen(chr(BaseBinaryFile::SEPARATOR_HEADER_DATA)) + BaseBinaryFile::LENGTH_COUNT + strlen(chr(BaseBinaryFile::SEPARATOR_HEADER_DATA)) + @@ -204,7 +240,7 @@ class BaseFileStack extends BaseStacker { // And pre-allocate a bit $this->getIteratorInstance()->preAllocateFile('file_stack'); - } // END - if + } // Load the file header $this->readFileHeader(); @@ -216,10 +252,13 @@ class BaseFileStack extends BaseStacker { * Get stack index instance. This can be used for faster * "defragmentation" and startup. */ - $indexInstance = FileStackIndexFactory::createFileStackIndexInstance($fileName, $type); + $indexInstance = FileStackIndexFactory::createFileStackIndexInstance($fileInfoInstance, $type); // And set it here $this->setIndexInstance($indexInstance); + + // Trace message + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FILE-STACK: EXIT!'); } /** @@ -229,20 +268,22 @@ class BaseFileStack extends BaseStacker { * @param $value Value to add to this stacker * @return void * @throws FullStackerException If the stack is full - */ - protected function addValue ($stackerName, $value) { - // Do some tests - if ($this->isStackFull($stackerName)) { + * @throws InvalidArgumentException If a parameter is not valid + * @throws InvalidArgumentException Not all variable types are wanted here + */ + protected function addValue (string $stackerName, $value) { + // Validate parameter + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: stackerName=%s,value[%s]=%s - CALLED!', $stackerName, gettype($value), print_r($value, true))); + if (empty($stackerName)) { + // No empty stack name + throw new InvalidArgumentException('Parameter "stackerName" is empty'); + } elseif ($this->isStackFull($stackerName)) { // Stacker is full throw new FullStackerException(array($this, $stackerName, $value), self::EXCEPTION_STACKER_IS_FULL); - } // END - if - - // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName . ',value[' . gettype($value) . ']=' . print_r($value, true)); - - // No objects/resources are allowed as their serialization takes to long - assert(!is_object($value)); - assert(!is_resource($value)); + } elseif (is_resource($value) || is_object($value)) { + // Not wanted type + throw new InvalidArgumentException(sprintf('value[]=%s is not supported', gettype($value))); + } /* * Now add the value to the file stack which returns gap position, a @@ -252,6 +293,9 @@ class BaseFileStack extends BaseStacker { // Add the hash and gap position to the index $this->getIndexInstance()->addHashToIndex($stackerName, $data); + + // Trace message + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FILE-STACK: EXIT!'); } /** @@ -259,20 +303,26 @@ class BaseFileStack extends BaseStacker { * * @param $stackerName Name of the stack * @return $value Value of last added value - * @throws EmptyStackerException If the stack is empty - */ - protected function getLastValue ($stackerName) { - // Is the stack not yet initialized or full? - if ($this->isStackEmpty($stackerName)) { + * @throws InvalidArgumentException If a parameter is not valid + * @throws BadMethodCallException If the stack is empty + */ + protected function getLastValue (string $stackerName) { + // Validate parameter + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: stackerName=%s - CALLED!', $stackerName)); + if (empty($stackerName)) { + // No empty stack name + throw new InvalidArgumentException('Parameter "stackerName" is empty'); + } elseif ($this->isStackEmpty($stackerName)) { // Throw an exception - throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY); - } // END - if + throw new BadMethodCallException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY); + } // Now get the last value /* NOISY-DEBUG: */ $this->partialStub('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName); $value = NULL; // Return it + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: value[]=%s - EXIT!', gettype($value))); return $value; } @@ -281,20 +331,26 @@ class BaseFileStack extends BaseStacker { * * @param $stackerName Name of the stack * @return $value Value of last added value - * @throws EmptyStackerException If the stack is empty - */ - protected function getFirstValue ($stackerName) { - // Is the stack not yet initialized or full? - if ($this->isStackEmpty($stackerName)) { + * @throws InvalidArgumentException If a parameter is not valid + * @throws BadMethodCallException If the stack is empty + */ + protected function getFirstValue (string $stackerName) { + // Validate parameter + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: stackerName=%s - CALLED!', $stackerName)); + if (empty($stackerName)) { + // No empty stack name + throw new InvalidArgumentException('Parameter "stackerName" is empty'); + } elseif ($this->isStackEmpty($stackerName)) { // Throw an exception - throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY); - } // END - if + throw new BadMethodCallException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY); + } // Now get the first value /* NOISY-DEBUG: */ $this->partialStub('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName); $value = NULL; // Return it + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: value[]=%s - EXIT!', gettype($value))); return $value; } @@ -303,14 +359,19 @@ class BaseFileStack extends BaseStacker { * * @param $stackerName Name of the stack * @return $value Value "poped" from array - * @throws EmptyStackerException If the stack is empty - */ - protected function popLast ($stackerName) { - // Is the stack not yet initialized or full? - if ($this->isStackEmpty($stackerName)) { + * @throws InvalidArgumentException If a parameter is not valid + * @throws BadMethodCallException If the stack is empty + */ + protected function popLast (string $stackerName) { + // Validate parameter + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: stackerName=%s - CALLED!', $stackerName)); + if (empty($stackerName)) { + // No empty stack name + throw new InvalidArgumentException('Parameter "stackerName" is empty'); + } elseif ($this->isStackEmpty($stackerName)) { // Throw an exception - throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY); - } // END - if + throw new BadMethodCallException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY); + } // Now, remove the last entry, we don't care about the return value here, see elseif() block above /* NOISY-DEBUG: */ $this->partialStub('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName); @@ -322,14 +383,19 @@ class BaseFileStack extends BaseStacker { * * @param $stackerName Name of the stack * @return $value Value "shifted" from array - * @throws EmptyStackerException If the named stacker is empty - */ - protected function popFirst ($stackerName) { - // Is the stack not yet initialized or full? - if ($this->isStackEmpty($stackerName)) { + * @throws InvalidArgumentException If a parameter is not valid + * @throws BadMethodCallException If the named stacker is empty + */ + protected function popFirst (string $stackerName) { + // Validate parameter + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: stackerName=%s - CALLED!', $stackerName)); + if (empty($stackerName)) { + // No empty stack name + throw new InvalidArgumentException('Parameter "stackerName" is empty'); + } elseif ($this->isStackEmpty($stackerName)) { // Throw an exception - throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY); - } // END - if + throw new BadMethodCallException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY); + } // Now, remove the last entry, we don't care about the return value here, see elseif() block above /* NOISY-DEBUG: */ $this->partialStub('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName); @@ -341,13 +407,22 @@ class BaseFileStack extends BaseStacker { * * @param $stackerName Name of the stack * @return $isFull Whether the stack is full + * @throws InvalidArgumentException If a parameter is not valid */ - protected function isStackFull ($stackerName) { - // File-based stacks will only run full if the disk space is low. + protected function isStackFull (string $stackerName) { + // Validate parameter + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: stackerName=%s - CALLED!', $stackerName)); + if (empty($stackerName)) { + // No empty stack name + throw new InvalidArgumentException('Parameter "stackerName" is empty'); + } + // @TODO Please implement this, returning false + /* NOISY-DEBUG: */ $this->partialStub('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName); $isFull = false; // Return result + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: isFull=%d - EXIT!', intval($isFull))); return $isFull; } @@ -356,13 +431,22 @@ class BaseFileStack extends BaseStacker { * * @param $stackerName Name of the stack * @return $isEmpty Whether the stack is empty - * @throws NoStackerException If given stack is missing + * @throws InvalidArgumentException If a parameter is not valid + * @throws BadMethodCallException If given stack is missing */ - public function isStackEmpty ($stackerName) { + public function isStackEmpty (string $stackerName) { + // Validate parameter + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: stackerName=%s - CALLED!', $stackerName)); + if (empty($stackerName)) { + // No empty stack name + throw new InvalidArgumentException('Parameter "stackerName" is empty'); + } + // So, is the stack empty? $isEmpty = (($this->getStackCount($stackerName)) == 0); // Return result + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: isEmpty=%d - EXIT!', intval($isEmpty))); return $isEmpty; } @@ -374,7 +458,7 @@ class BaseFileStack extends BaseStacker { * @return void * @throws UnsupportedOperationException This method is not (and maybe never will be) supported */ - public function initStack ($stackerName, $forceReInit = false) { + public function initStack (string $stackerName, bool $forceReInit = false) { throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION); } @@ -384,7 +468,7 @@ class BaseFileStack extends BaseStacker { * @return void * @throws UnsupportedOperationException This method is not (and maybe never will be) supported */ - public function initStacks (array $stacks, $forceReInit = false) { + public function initStacks (array $stacks, bool $forceReInit = false) { throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION); } @@ -395,7 +479,7 @@ class BaseFileStack extends BaseStacker { * @return $isInitialized Whether the stack is initialized * @throws UnsupportedOperationException This method is not (and maybe never will be) supported */ - public function isStackInitialized ($stackerName) { + public function isStackInitialized (string $stackerName) { throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION); } @@ -415,9 +499,14 @@ class BaseFileStack extends BaseStacker { * @param $stackerName Name of the stack * @return $count Size of stack (array count) */ - public function getStackCount ($stackerName) { + public function getStackCount (string $stackerName) { // Now, simply return the found count value, this must be up-to-date then! - return $this->getIteratorInstance()->getCounter(); + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: stackerName=%s - CALLED!', $stackerName)); + $count = $this->getIteratorInstance()->getCounter(); + + // Return count + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: count=%d - EXIT!', $count)); + return $count; } /** @@ -426,17 +515,22 @@ class BaseFileStack extends BaseStacker { * @return $length Minimum length for one entry/block */ public function calculateMinimumBlockLength () { - // Calulcate it - $length = - // Length of entry group - BaseBinaryFile::LENGTH_GROUP + strlen(chr(BaseBinaryFile::SEPARATOR_GROUP_HASH)) + - // Hash + value - self::getHashLength() + strlen(chr(BaseBinaryFile::SEPARATOR_HASH_VALUE)) + 1 + - // Final separator - strlen(chr(BaseBinaryFile::SEPARATOR_ENTRIES)); + // Is the value "cached"? + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FILE-STACK: CALLED!'); + if (self::$minimumBlockLength == 0) { + // Calulcate it + self::$minimumBlockLength = + // Length of entry group + BaseBinaryFile::LENGTH_GROUP + strlen(chr(BaseBinaryFile::SEPARATOR_GROUP_HASH)) + + // Hash + value + self::getHashLength() + strlen(chr(BaseBinaryFile::SEPARATOR_HASH_VALUE)) + 1 + + // Final separator + strlen(chr(BaseBinaryFile::SEPARATOR_ENTRIES)); + } // Return it - return $length; + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: self::minimumBlockLength=%d - EXIT!', self::$minimumBlockLength)); + return self::$minimumBlockLength; } /** @@ -469,7 +563,7 @@ class BaseFileStack extends BaseStacker { * @return void * @throws UnsupportedOperationException This method is not (and maybe never will be) supported */ - public final function setHeaderSize ($headerSize) { + public final function setHeaderSize (int $headerSize) { throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION); } @@ -523,8 +617,8 @@ class BaseFileStack extends BaseStacker { * @return void * @throws UnsupportedOperationException This method is not (and maybe never will be) supported */ - public function writeData ($seekPosition, $data, $flushHeader = true) { - /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] seekPosition=%s,data[]=%s,flushHeader=%d', __METHOD__, __LINE__, $seekPosition, gettype($data), intval($flushHeader))); + public function writeData (int $seekPosition, string $data, bool $flushHeader = true) { + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: seekPosition=%s,data[]=%s,flushHeader=%d', $seekPosition, gettype($data), intval($flushHeader))); throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION); } @@ -536,8 +630,8 @@ class BaseFileStack extends BaseStacker { * @return $data Hash and gap position * @throws UnsupportedOperationException This method is not (and maybe never will be) supported */ - public function writeValueToFile ($groupId, $value) { - /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] groupId=%s,value[%s]=%s', __METHOD__, __LINE__, $groupId, gettype($value), print_r($value, true))); + public function writeValueToFile (string $groupId, $value) { + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: groupId=%s,value[%s]=%s', $groupId, gettype($value), print_r($value, true))); throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION); } @@ -549,8 +643,9 @@ class BaseFileStack extends BaseStacker { * @return $seekPosition Found next gap's seek position * @throws UnsupportedOperationException This method is not (and maybe never will be) supported */ - public function searchNextGap ($length) { - /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] length=%s', __METHOD__, __LINE__, $length)); + public function searchNextGap (int $length) { + // Not supported here + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: length=%d - CALLED!', $length)); throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION); } @@ -561,7 +656,12 @@ class BaseFileStack extends BaseStacker { */ public function getFileSize () { // Call iterator's method - return $this->getIteratorInstance()->getFileSize(); + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FILE-STACK: CALLED!'); + $size = $this->getIteratorInstance()->getFileSize(); + + // Return size + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: size=%d - EXIT!', $size)); + return $size; } /** @@ -572,11 +672,9 @@ class BaseFileStack extends BaseStacker { * @param $encoded Encoded value to be written to the file * @return $data Gap position and length of the raw data */ - public function writeDataToFreeGap ($groupId, $hash, $encoded) { - // Debug message - /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] groupId=%s,hash=%s,encoded()=%d - CALLED!', __METHOD__, __LINE__, $groupId, $hash, strlen($encoded))); - + public function writeDataToFreeGap (string $groupId, string $hash, string $encoded) { // Raw data been written to the file + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: groupId=%s,hash=%s,encoded()=%d - CALLED!', $groupId, $hash, strlen($encoded))); $rawData = sprintf('%s%s%s%s%s', $groupId, BaseBinaryFile::SEPARATOR_GROUP_HASH, @@ -585,30 +683,32 @@ class BaseFileStack extends BaseStacker { $encoded ); - // Debug message - /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] groupId=%s,hash=%s,rawData()=%d', __METHOD__, __LINE__, $groupId, $hash, strlen($rawData))); - // Search for next free gap + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: groupId=%s,hash=%s,rawData()=%d', $groupId, $hash, strlen($rawData))); $gapPosition = $this->getIteratorInstance()->searchNextGap(strlen($rawData)); // Gap position cannot be smaller than header length + 1 - assert($gapPosition > $this->getIteratorInstance()->getHeaderSize()); - - // Debug message - /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] groupId=%s,hash=%s,gapPosition=%s', __METHOD__, __LINE__, $groupId, $hash, $gapPosition)); + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: gapPosition=%d', $gapPosition)); + if ($gapPosition <= $this->getIteratorInstance()->getHeaderSize()) { + // Improper gap position + throw new UnexpectedValueException(sprintf('gapPosition[%s]=%d is not larger than headerSize=%d', + gettype($gapPosition), + $gapPosition, + $this->getIteratorInstance()->getHeaderSize() + )); + } // Then write the data at that gap + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: groupId=%s,hash=%s,gapPosition=%s', $groupId, $hash, $gapPosition)); $this->getIteratorInstance()->writeData($gapPosition, $rawData); - // Debug message - /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] groupId=%s,hash=%s,rawData()=%d - EXIT!', __METHOD__, __LINE__, $groupId, $hash, strlen($rawData))); - // Return gap position, hash and length of raw data - return array( - self::ARRAY_INDEX_GAP_POSITION => $gapPosition, - self::ARRAY_INDEX_HASH => $hash, - self::ARRAY_INDEX_DATA_LENGTH => strlen($rawData) - ); + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: groupId=%s,hash=%s,rawData()=%d - EXIT!', $groupId, $hash, strlen($rawData))); + return [ + self::ARRAY_NAME_GAP_POSITION => $gapPosition, + self::ARRAY_NAME_HASH => $hash, + self::ARRAY_NAME_DATA_LENGTH => strlen($rawData), + ]; } }