<?php
// Own namespace
-namespace Org\Mxchange\CoreFramework\Stacker\Filesystem;
+namespace Org\Mxchange\CoreFramework\Stack\File;
// Import framework stuff
-use Org\Mxchange\CoreFramework\Factory\Filesystem\Stack\FileStackIndexFactory;
+use Org\Mxchange\CoreFramework\Factory\Stack\File\FileStackIndexFactory;
use Org\Mxchange\CoreFramework\Factory\ObjectFactory;
-use Org\Mxchange\CoreFramework\FileStack\InvalidMagicException;
use Org\Mxchange\CoreFramework\Filesystem\File\BaseBinaryFile;
use Org\Mxchange\CoreFramework\Generic\UnsupportedOperationException;
-use Org\Mxchange\CoreFramework\Index\Indexable;
use Org\Mxchange\CoreFramework\Iterator\Filesystem\SeekableWritableFileIterator;
-use Org\Mxchange\CoreFramework\Stacker\BaseStacker;
+use Org\Mxchange\CoreFramework\Stack\BaseStacker;
+use Org\Mxchange\CoreFramework\Stack\File\InvalidMagicException;
+use Org\Mxchange\CoreFramework\Stack\File\StackableFile;
+use Org\Mxchange\CoreFramework\Traits\Index\IndexableTrait;
use Org\Mxchange\CoreFramework\Traits\Iterator\IteratorTrait;
use Org\Mxchange\CoreFramework\Utils\String\StringUtils;
// Import SPL stuff
+use \InvalidArgumentException;
use \SplFileInfo;
use \UnexpectedValueException;
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-abstract class BaseFileStack extends BaseStacker {
+abstract class BaseFileStack extends BaseStacker implements StackableFile {
// Load traits
+ use IndexableTrait;
use IteratorTrait;
// Exception codes
const EXCEPTION_BAD_MAGIC = 0xe100;
/**
- * Magic for this stack
+ * Minimum block length
*/
- const STACK_MAGIC = 'STACKv0.1';
-
- /**
- * Name of array index for gap position
- */
- const ARRAY_INDEX_GAP_POSITION = 'gap';
-
- /**
- * Name of array index for hash
- */
- const ARRAY_INDEX_HASH = 'hash';
-
- /**
- * Name of array index for length of raw data
- */
- const ARRAY_INDEX_DATA_LENGTH = 'length';
-
- /**
- * An instance of an Indexable class
- */
- private $indexInstance = NULL;
+ private static $minimumBlockLength = 0;
/**
* Protected constructor
parent::__construct($className);
}
- /**
- * Setter for Indexable instance
- *
- * @param $indexInstance An instance of an Indexable class
- * @return void
- */
- protected final function setIndexInstance (Indexable $indexInstance) {
- $this->indexInstance = $indexInstance;
- }
-
- /**
- * Getter for Indexable instance
- *
- * @return $indexInstance An instance of an Indexable class
- */
- public final function getIndexInstance () {
- return $this->indexInstance;
- }
-
/**
* Reads the file header
*
*/
public function readFileHeader () {
// First rewind to beginning as the header sits at the beginning ...
- /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: CALLED!', __METHOD__, __LINE__));
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FILE-STACK: CALLED!');
$this->getIteratorInstance()->rewind();
// Then read it (see constructor for calculation)
*/
$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('BASE-FILE-STACK: header(%d)=%s', count($header), print_r($header, true)));
if (count($header) != 3) {
$data,
count($header)
));
- } elseif ($header[0] != self::STACK_MAGIC) {
+ } elseif ($header[0] != StackableFile::STACK_MAGIC) {
// Bad magic
throw new InvalidMagicException($data, self::EXCEPTION_BAD_MAGIC);
}
$header[1] = hex2bin($header[1]);
$header[2] = hex2bin($header[2]);
+ // Set header here
+ $this->getIteratorInstance()->setHeader($header);
+
// Trace message
/* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: EXIT!', __METHOD__, __LINE__));
}
*/
public function flushFileHeader () {
// Put all informations together
- /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: CALLED!', __METHOD__, __LINE__));
+ /* 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),
$this->getIteratorInstance()->writeData(0, $header, false);
// Trace message
- /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: EXIT!', __METHOD__, __LINE__));
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FILE-STACK: EXIT!');
}
/**
* @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 (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
- /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-FILE-STACK: fileInfoInstance=%s,type=%s - CALLED!', $fileInfoInstance, $type));
- $fileInstance = ObjectFactory::createObjectByConfiguredName('stack_file_class', array($fileInfoInstance, $this));
+ $stackInstance = ObjectFactory::createObjectByConfiguredName('stack_file_class', array($fileInfoInstance, $this));
// Get iterator instance
- $iteratorInstance = ObjectFactory::createObjectByConfiguredName('file_iterator_class', array($fileInstance));
+ $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)) +
// And set it here
$this->setIndexInstance($indexInstance);
+
+ // Trace message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FILE-STACK: EXIT!');
}
/**
* @param $value Value to add to this stacker
* @return void
* @throws FullStackerException If the stack is full
+ * @throws InvalidArgumentException If a parameter is not valid
* @throws InvalidArgumentException Not all variable types are wanted here
*/
protected function addValue (string $stackerName, $value) {
- // Do some tests
- /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('stackerName=%s,value[%s]=%s - CALLED!', $stackerName, gettype($value), print_r($value, true)));
- if ($this->isStackFull($stackerName)) {
+ // 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);
} elseif (is_resource($value) || is_object($value)) {
// 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!');
}
/**
*
* @param $stackerName Name of the stack
* @return $value Value of last added value
+ * @throws InvalidArgumentException If a parameter is not valid
* @throws BadMethodCallException If the stack is empty
*/
protected function getLastValue (string $stackerName) {
- // Is the stack not yet initialized or full?
- if ($this->isStackEmpty($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 BadMethodCallException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
- } // END - if
+ }
// 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;
}
*
* @param $stackerName Name of the stack
* @return $value Value of last added value
+ * @throws InvalidArgumentException If a parameter is not valid
* @throws BadMethodCallException If the stack is empty
*/
protected function getFirstValue (string $stackerName) {
- // Is the stack not yet initialized or full?
- if ($this->isStackEmpty($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 BadMethodCallException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
- } // END - if
+ }
// 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;
}
*
* @param $stackerName Name of the stack
* @return $value Value "poped" from array
+ * @throws InvalidArgumentException If a parameter is not valid
* @throws BadMethodCallException If the stack is empty
*/
protected function popLast (string $stackerName) {
- // Is the stack not yet initialized or full?
- if ($this->isStackEmpty($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 BadMethodCallException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
- } // END - if
+ }
// 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);
*
* @param $stackerName Name of the stack
* @return $value Value "shifted" from array
+ * @throws InvalidArgumentException If a parameter is not valid
* @throws BadMethodCallException If the named stacker is empty
*/
protected function popFirst (string $stackerName) {
- // Is the stack not yet initialized or full?
- if ($this->isStackEmpty($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 BadMethodCallException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
- } // END - if
+ }
// 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);
*
* @param $stackerName Name of the stack
* @return $isFull Whether the stack is full
+ * @throws InvalidArgumentException If a parameter is not valid
*/
protected function isStackFull (string $stackerName) {
- // File-based stacks will only run full if the disk space is low.
+ // 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;
}
*
* @param $stackerName Name of the stack
* @return $isEmpty Whether the stack is empty
+ * @throws InvalidArgumentException If a parameter is not valid
* @throws BadMethodCallException If given stack is missing
*/
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;
}
*/
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;
}
/**
* @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;
}
/**
*/
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;
}
/**
$gapPosition = $this->getIteratorInstance()->searchNextGap(strlen($rawData));
// Gap position cannot be smaller than header length + 1
+ /* 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',
// Return gap position, hash and length of raw data
/* 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_INDEX_GAP_POSITION => $gapPosition,
- self::ARRAY_INDEX_HASH => $hash,
- self::ARRAY_INDEX_DATA_LENGTH => strlen($rawData),
+ self::ARRAY_NAME_GAP_POSITION => $gapPosition,
+ self::ARRAY_NAME_HASH => $hash,
+ self::ARRAY_NAME_DATA_LENGTH => strlen($rawData),
];
}