Could generalize ("generic") more code which avoid some duplicate fields and methods...
authorRoland Haeder <roland@mxchange.org>
Tue, 20 May 2014 18:27:45 +0000 (20:27 +0200)
committerRoland Haeder <roland@mxchange.org>
Tue, 20 May 2014 18:27:45 +0000 (20:27 +0200)
Signed-off-by: Roland H├Ąder <roland@mxchange.org>
inc/classes/main/class_BaseFrameworkSystem.php
inc/classes/main/index/class_BaseIndex.php
inc/classes/main/stacker/file/class_BaseFileStack.php

index d7fc5dd7c1bc739e0de3d5acec6a29905ae950ee..2190622418c9ef09505255f67a29e7f326330eae 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 class BaseFrameworkSystem extends stdClass implements FrameworkInterface {
+       /**
+        * Length of count
+        */
+       const LENGTH_COUNT = 20;
+
+       /**
+        * Length of position
+        */
+       const LENGTH_POSITION = 20;
+
        /**
         * The real class name
         */
@@ -213,6 +223,36 @@ class BaseFrameworkSystem extends stdClass implements FrameworkInterface {
         */
        private static $hashLength = NULL;
 
+       /**
+        * Counter for total entries
+        */
+       private $totalEntries = 0;
+
+       /**
+        * Current seek position
+        */
+       private $seekPosition = 0;
+
+       /**
+        * Size of header
+        */
+       private $headerSize = 0;
+
+       /**
+        * File header
+        */
+       private $header = array();
+
+       /**
+        * Seek positions for gaps ("fragmentation")
+        */
+       private $gaps = array();
+
+       /**
+        * Seek positions for damaged entries (e.g. mismatching hash sum, ...)
+        */
+       private $damagedEntries = array();
+
        /***********************
         * Exception codes.... *
         ***********************/
@@ -2802,6 +2842,363 @@ class BaseFrameworkSystem extends stdClass implements FrameworkInterface {
                // ... and return it
                return $translated;
        }
+
+       /**
+        * Protected constructor
+        *
+        * @param       $className      Name of the class
+        * @return      void
+        */
+       protected function __construct ($className) {
+               // Call parent constructor
+               parent::__construct($className);
+
+               // Init counters and gaps array
+               $this->initCountersGapsArray();
+       }
+
+       /**
+        * Initializes counter for valid entries, arrays for damaged entries and
+        * an array for gap seek positions. If you call this method on your own,
+        * please re-analyze the file structure. So you are better to call
+        * analyzeFile() instead of this method.
+        *
+        * @return      void
+        */
+       protected function initCountersGapsArray () {
+               // Init counter and seek position
+               $this->setCounter(0);
+               $this->setSeekPosition(0);
+
+               // Init arrays
+               $this->gaps = array();
+               $this->damagedEntries = array();
+       }
+
+       /**
+        * Getter for total entries
+        *
+        * @return      $totalEntries   Total entries in this file
+        */
+       protected final function getCounter () {
+               // Get it
+               return $this->totalEntries;
+       }
+
+       /**
+        * Setter for total entries
+        *
+        * @param       $totalEntries   Total entries in this file
+        * @return      void
+        */
+       protected final function setCounter ($counter) {
+               // Set it
+               $this->totalEntries = $counter;
+       }
+
+       /**
+        * Increment counter
+        *
+        * @return      void
+        */
+       protected final function incrementCounter () {
+               // Get it
+               $this->totalEntries++;
+       }
+
+       /**
+        * Getter for header size
+        *
+        * @return      $totalEntries   Size of file header
+        */
+       protected final function getHeaderSize () {
+               // Get it
+               return $this->headerSize;
+       }
+
+       /**
+        * Setter for header size
+        *
+        * @param       $headerSize             Size of file header
+        * @return      void
+        */
+       protected final function setHeaderSize ($headerSize) {
+               // Set it
+               $this->headerSize = $headerSize;
+       }
+
+       /**
+        * Getter for seek position
+        *
+        * @return      $seekPosition   Current seek position (stored here in object)
+        */
+       protected final function getSeekPosition () {
+               // Get it
+               return $this->seekPosition;
+       }
+
+       /**
+        * Setter for seek position
+        *
+        * @param       $seekPosition   Current seek position (stored here in object)
+        * @return      void
+        */
+       protected final function setSeekPosition ($seekPosition) {
+               // And set it
+               $this->seekPosition = $seekPosition;
+       }
+
+       /**
+        * Updates seekPosition attribute from file to avoid to much access on file.
+        *
+        * @return      void
+        */
+       protected function updateSeekPosition () {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+
+               // Get key (= seek position)
+               $seekPosition = $this->getIteratorInstance()->key();
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Setting seekPosition=%s', __METHOD__, __LINE__, $seekPosition));
+
+               // And set it here
+               $this->setSeekPosition($seekPosition);
+
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+       }
+
+       /**
+        * Reads the file header
+        *
+        * @return      void
+        */
+       protected function readFileHeader () {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+
+               // First rewind to beginning as the header sits at the beginning ...
+               $this->getIteratorInstance()->rewind();
+
+               // Then read it (see constructor for calculation)
+               $data = $this->getIteratorInstance()->read($this->getHeaderSize());
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Read %d bytes (%d wanted).', __METHOD__, __LINE__, strlen($data), $this->getHeaderSize()));
+
+               // Have all requested bytes been read?
+               assert(strlen($data) == $this->getHeaderSize());
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
+
+               // Last character must be the separator
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] data(-1)=%s', __METHOD__, __LINE__, dechex(ord(substr($data, -1, 1)))));
+               assert(substr($data, -1, 1) == chr(self::SEPARATOR_HEADER_ENTRIES));
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
+
+               // Okay, then remove it
+               $data = substr($data, 0, -1);
+
+               // And update seek position
+               $this->updateSeekPosition();
+
+               /*
+                * Now split it:
+                *
+                * 0 => Magic
+                * 1 => Total entries
+                * 2 => Current seek position
+                */
+               $this->header = explode(chr(self::SEPARATOR_HEADER_DATA), $data);
+
+               // Check if the array has only 3 elements
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] header(%d)=%s', __METHOD__, __LINE__, count($this->header), print_r($this->header, TRUE)));
+               assert(count($this->header) == 3);
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
+
+               // Check magic
+               assert($this->header[0] == self::STACK_MAGIC);
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
+
+               // Check length of count and seek position
+               assert(strlen($this->header[1]) == self::LENGTH_COUNT);
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
+               assert(strlen($this->header[2]) == self::LENGTH_POSITION);
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
+
+               // Decode count and seek position
+               $this->header[1] = hex2bin($this->header[1]);
+               $this->header[2] = hex2bin($this->header[2]);
+
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+       }
+
+       /**
+        * Checks whether the file header is initialized
+        *
+        * @return      $isInitialized  Whether the file header is initialized
+        */
+       protected function isFileHeaderInitialized () {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+               // Default is not initialized
+               $isInitialized = FALSE;
+
+               // Is the file initialized?
+               if ($this->isFileInitialized()) {
+                       // Some bytes has been written, so rewind to start of it.
+                       $rewindStatus = $this->getIteratorInstance()->rewind();
+                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] rewindStatus=%s', __METHOD__, __LINE__, $rewindStatus));
+
+                       // Is the rewind() call successfull?
+                       if ($rewindStatus != 1) {
+                               // Something bad happened
+                               self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Could not rewind().', __METHOD__, __LINE__));
+                       } // END - if
+
+                       // Read file header
+                       $this->readFileHeader();
+
+                       // The above method does already check the header
+                       $isInitialized = TRUE;
+               } // END - if
+
+               // Return result
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] isInitialized=%d - EXIT!', __METHOD__, __LINE__, intval($isInitialized)));
+               return $isInitialized;
+       }
+
+       /**
+        * Checks whether the assigned file has been initialized
+        *
+        * @return      $isInitialized          Whether the file's size is zero
+        */
+       protected function isFileInitialized () {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+
+               // Get it from iterator which holds the pointer instance. If FALSE is returned
+               $fileSize = $this->getIteratorInstance()->size();
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] fileSize=%s', __METHOD__, __LINE__, $fileSize));
+
+               /*
+                * The returned file size should not be FALSE or NULL as this means
+                * that the pointer class does not work correctly.
+                */
+               assert(is_int($fileSize));
+
+               // Is more than 0 returned?
+               $isInitialized = ($fileSize > 0);
+
+               // Return result
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] isInitialized=%d - EXIT!', __METHOD__, __LINE__, intval($isInitialized)));
+               return $isInitialized;
+       }
+
+       /**
+        * Creates the assigned file
+        *
+        * @return      void
+        */
+       protected function createFileHeader () {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+               // The file's header should not be initialized here
+               assert(!$this->isFileHeaderInitialized());
+
+               // Simple flush file header which will create it.
+               $this->flushFileHeader();
+
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!!', __METHOD__, __LINE__));
+       }
+
+       /**
+        * Flushes the file header
+        *
+        * @return      void
+        */
+       protected function flushFileHeader () {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+
+               // Put all informations together
+               $header = sprintf('%s%s%s%s%s%s',
+                       // Magic
+                       self::STACK_MAGIC,
+
+                       // Separator magic<->count
+                       chr(self::SEPARATOR_HEADER_DATA),
+
+                       // Total entries (will be zero) and pad it to 20 chars
+                       str_pad($this->dec2hex($this->getCounter()), self::LENGTH_COUNT, '0', STR_PAD_LEFT),
+
+                       // Separator count<->seek position
+                       chr(self::SEPARATOR_HEADER_DATA),
+
+                       // Position (will be zero)
+                       str_pad($this->dec2hex($this->getSeekPosition(), 2), self::LENGTH_POSITION, '0', STR_PAD_LEFT),
+
+                       // Separator position<->entries
+                       chr(self::SEPARATOR_HEADER_ENTRIES)
+               );
+
+               // Write it to disk (header is always at seek position 0)
+               $this->writeData(0, $header);
+
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+       }
+
+       /**
+        * Writes data at given position
+        *
+        * @param       $seekPosition   Seek position
+        * @param       $data                   Data to be written
+        * @return      void
+        */
+       protected function writeData ($seekPosition, $data) {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] seekPosition=%s,data()=%s - CALLED!', __METHOD__, __LINE__, $seekPosition, strlen($data)));
+
+               // Write data at given position
+               $this->getIteratorInstance()->writeAtPosition($seekPosition, $data);
+
+               // Update seek position
+               $this->updateSeekPosition();
+
+               // Flush header
+               $this->flushHeader();
+
+               // Seek to old position
+               $this->seekToOldPosition();
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+       }
+
+       /**
+        * Pre-allocates file (if enabled) with some space for later faster write access.
+        *
+        * @param       $type   Type of the file
+        * @return      void
+        */
+       protected function preAllocateFile ($type) {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+
+               // Is it enabled?
+               if ($this->getConfigInstance()->getConfigEntry($type . '_pre_allocate_enabled') != 'Y') {
+                       // Not enabled
+                       self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Not pre-allocating file.', __METHOD__, __LINE__));
+
+                       // Don't continue here.
+                       return;
+               } // END - if
+
+               // Message to user
+               self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Pre-allocating file ...', __METHOD__, __LINE__));
+
+               /*
+                * Calculate minimum length for one entry:
+                * minimum length = hash length + separator + name + minimum entry size = ?? + 1 + 10 + 1 = ??
+                */
+               $minLengthEntry = self::getHashLength() + strlen(self::SEPARATOR_HASH_NAME) + self::LENGTH_NAME + 1;
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] minLengthEntry=%s', __METHOD__, __LINE__, $minLengthEntry));
+
+               // Calulcate seek position
+               $seekPosition = $minLengthEntry * $this->getConfigInstance()->getConfigEntry($type . '_pre_allocate_count');
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] seekPosition=%s', __METHOD__, __LINE__, $seekPosition));
+
+               // Now simply write a NUL there. This will pre-allocate the file.
+               $this->writeData($seekPosition, chr(0));
+
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+       }
 }
 
 // [EOF]
index 9d019528a4f188d15822e7bcb98899573c4e44f1..046ec73613b8910e413be723767eff1d7ae4a2d8 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 class BaseIndex extends BaseFrameworkSystem {
+       /**
+        * Magic for this index
+        */
+       const INDEX_MAGIC = 'INDEXv0.1';
+
+       /**
+        * Separator for header data
+        */
+       const SEPARATOR_HEADER_DATA = 0x01;
+
+       /**
+        * Separator header->entries
+        */
+       const SEPARATOR_HEADER_ENTRIES = 0x02;
+
        /**
         * Protected constructor
         *
@@ -31,16 +46,185 @@ class BaseIndex extends BaseFrameworkSystem {
        protected function __construct ($className) {
                // Call parent constructor
                parent::__construct($className);
+
+               // Calculate header size
+               $this->setHeaderSize(
+                       strlen(self::INDEX_MAGIC) +
+                       strlen(self::SEPARATOR_HEADER_DATA) +
+                       self::LENGTH_COUNT +
+                       strlen(self::SEPARATOR_HEADER_ENTRIES)
+               );
        }
 
        /**
-        * Initializes this file based index
+        * Reads the file header
         *
-        * @param       $fileName       Name of the file to create an index for
+        * @return      void
+        */
+       private function readFileHeader () {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+
+               // First rewind to beginning as the header sits at the beginning ...
+               $this->getIteratorInstance()->rewind();
+
+               // Then read it (see constructor for calculation)
+               $data = $this->getIteratorInstance()->read($this->headerSize);
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Read %d bytes (%d wanted).', __METHOD__, __LINE__, strlen($data), $this->headerSize));
+
+               // Have all requested bytes been read?
+               assert(strlen($data) == $this->headerSize);
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
+
+               // Last character must be the separator
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] data(-1)=%s', __METHOD__, __LINE__, dechex(ord(substr($data, -1, 1)))));
+               assert(substr($data, -1, 1) == chr(self::SEPARATOR_HEADER_ENTRIES));
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
+
+               // Okay, then remove it
+               $data = substr($data, 0, -1);
+
+               // And update seek position
+               $this->updateSeekPosition();
+
+               /*
+                * Now split it:
+                *
+                * 0 => magic
+                * 1 => total entries
+                */
+               $this->header = explode(chr(self::SEPARATOR_HEADER_DATA), $data);
+
+               // Check if the array has only 3 elements
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] header(%d)=%s', __METHOD__, __LINE__, count($this->header), print_r($this->header, TRUE)));
+               assert(count($this->header) == 2);
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
+
+               // Check magic
+               assert($this->header[0] == self::INDEX_MAGIC);
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
+
+               // Check length of count
+               assert(strlen($this->header[1]) == self::LENGTH_COUNT);
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
+
+               // Decode count
+               $this->header[1] = hex2bin($this->header[1]);
+
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+       }
+
+       /**
+        * Checks whether the file header is initialized
+        *
+        * @return      $isInitialized  Whether the file header is initialized
+        */
+       private function isFileHeaderInitialized () {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+               // Default is not initialized
+               $isInitialized = FALSE;
+
+               // Is the file initialized?
+               if ($this->isFileInitialized()) {
+                       // Some bytes has been written, so rewind to start of it.
+                       $rewindStatus = $this->getIteratorInstance()->rewind();
+                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] rewindStatus=%s', __METHOD__, __LINE__, $rewindStatus));
+
+                       // Is the rewind() call successfull?
+                       if ($rewindStatus != 1) {
+                               // Something bad happened
+                               self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Could not rewind().', __METHOD__, __LINE__));
+                       } // END - if
+
+                       // Read file header
+                       $this->readFileHeader();
+
+                       // The above method does already check the header
+                       $isInitialized = TRUE;
+               } // END - if
+
+               // Return result
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] isInitialized=%d - EXIT!', __METHOD__, __LINE__, intval($isInitialized)));
+               return $isInitialized;
+       }
+
+       /**
+        * Flushes the file header
+        *
+        * @return      void
+        */
+       private function flushFileHeader () {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+
+               // Put all informations together
+               $header = sprintf('%s%s',
+                       // Magic
+                       self::INDEX_MAGIC,
+
+                       // Separator position<->entries
+                       chr(self::SEPARATOR_HEADER_ENTRIES)
+               );
+
+               // Write it to disk (header is always at seek position 0)
+               $this->writeData(0, $header);
+
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+       }
+
+       /**
+        * Analyzes entries in index file. This will count all found (and valid)
+        * entries, mark invalid as damaged and count gaps ("fragmentation"). If
+        * only gaps are found, the file is considered as "virgin" (no entries).
+        *
+        * @return      void
+        */
+       private function analyzeFile () {
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+
+               // Make sure the file is initialized
+               assert($this->isFileInitialized());
+
+               // Init counters and gaps array
+               $this->initGapsArray();
+
+               // Output message (as this may take some time)
+               self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Analyzing file structure ... (this may take some time)', __METHOD__, __LINE__));
+
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+       }
+
+       /**
+        * Initializes this index
+        *
+        * @param       $fileName       File name of this index
         * @return      void
         */
        protected function initIndex ($fileName) {
-               // @TODO
+               // Get a file i/o pointer instance for index file
+               $pointerInstance = ObjectFactory::createObjectByConfiguredName('file_raw_input_output_class', array($fileName));
+
+               // Get iterator instance
+               $iteratorInstance = ObjectFactory::createObjectByConfiguredName('file_io_iterator_class', array($pointerInstance));
+
+               // Is the instance implementing the right interface?
+               assert($iteratorInstance instanceof SeekableWritableFileIterator);
+
+               // Set iterator here
+               $this->setIteratorInstance($iteratorInstance);
+
+               // Is the file's header initialized?
+               if (!$this->isFileHeaderInitialized()) {
+                       // No, then create it (which may pre-allocate the index)
+                       $this->createFileHeader();
+
+                       // And pre-allocate a bit
+                       $this->preAllocateFile('index');
+               } // END - if
+
+               // Load the file header
+               $this->readFileHeader();
+
+               // Count all entries in file
+               $this->analyzeFile();
        }
 }
 
index e3aeb4701fb9c3f192b7fa9cec788448e13cfb61..c14743b32f84900e82a496edc02e97711f8e407d 100644 (file)
@@ -47,46 +47,6 @@ class BaseFileStack extends BaseStacker {
         */
        const LENGTH_NAME = 10;
 
-       /**
-        * Length of count
-        */
-       const LENGTH_COUNT = 20;
-
-       /**
-        * Length of position
-        */
-       const LENGTH_POSITION = 20;
-
-       /**
-        * Counter for total entries
-        */
-       private $totalEntries = 0;
-
-       /**
-        * Current seek position
-        */
-       private $seekPosition = 0;
-
-       /**
-        * Size of header
-        */
-       private $headerSize = 0;
-
-       /**
-        * File header
-        */
-       private $header = array();
-
-       /**
-        * Seek positions for gaps ("fragmentation")
-        */
-       private $gaps = array();
-
-       /**
-        * Seek positions for damaged entries (e.g. mismatching hash sum, ...)
-        */
-       private $damagedEntries = array();
-
        /**
         * Protected constructor
         *
@@ -98,7 +58,7 @@ class BaseFileStack extends BaseStacker {
                parent::__construct($className);
 
                // Calculate header size
-               $this->headerSize = (
+               $this->setHeaderSize(
                        strlen(self::STACK_MAGIC) +
                        strlen(self::SEPARATOR_HEADER_DATA) +
                        self::LENGTH_COUNT +
@@ -111,94 +71,6 @@ class BaseFileStack extends BaseStacker {
                $this->initCountersGapsArray();
        }
 
-       /**
-        * Initializes counter for valid entries, arrays for damaged entries and
-        * an array for gap seek positions. If you call this method on your own,
-        * please re-analyze the file structure. So you are better to call
-        * analyzeStackFile() instead of this method.
-        *
-        * @return      void
-        */
-       private function initCountersGapsArray () {
-               // Init counter and seek position
-               $this->setCounter(0);
-               $this->setSeekPosition(0);
-
-               // Init arrays
-               $this->gaps = array();
-               $this->damagedEntries = array();
-       }
-
-       /**
-        * Getter for total entries
-        *
-        * @return      $totalEntries   Total entries in this stack
-        */
-       private final function getCounter () {
-               // Get it
-               return $this->totalEntries;
-       }
-
-       /**
-        * Setter for total entries
-        *
-        * @param       $totalEntries   Total entries in this stack
-        * @return      void
-        */
-       private final function setCounter ($counter) {
-               // Set it
-               $this->totalEntries = $counter;
-       }
-
-       /**
-        * Increment counter
-        *
-        * @return      void
-        */
-       private final function incrementCounter () {
-               // Get it
-               $this->totalEntries++;
-       }
-
-       /**
-        * Getter for seek position
-        *
-        * @return      $seekPosition   Current seek position (stored here in object)
-        */
-       private final function getSeekPosition () {
-               // Get it
-               return $this->seekPosition;
-       }
-
-       /**
-        * Setter for seek position
-        *
-        * @param       $seekPosition   Current seek position (stored here in object)
-        * @return      void
-        */
-       private final function setSeekPosition ($seekPosition) {
-               // And set it
-               $this->seekPosition = $seekPosition;
-       }
-
-       /**
-        * Updates seekPosition attribute from file to avoid to much access on file.
-        *
-        * @return      void
-        */
-       private function updateSeekPosition () {
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
-
-               // Get key (= seek position)
-               $seekPosition = $this->getIteratorInstance()->key();
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Setting seekPosition=%s', __METHOD__, __LINE__, $seekPosition));
-
-               // And set it here
-               $this->setSeekPosition($seekPosition);
-
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
-       }
-
        /**
         * Reads the file header
         *
@@ -211,11 +83,11 @@ class BaseFileStack extends BaseStacker {
                $this->getIteratorInstance()->rewind();
 
                // Then read it (see constructor for calculation)
-               $data = $this->getIteratorInstance()->read($this->headerSize);
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Read %d bytes (%d wanted).', __METHOD__, __LINE__, strlen($data), $this->headerSize));
+               $data = $this->getIteratorInstance()->read($this->getHeaderSize());
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Read %d bytes (%d wanted).', __METHOD__, __LINE__, strlen($data), $this->getHeaderSize()));
 
                // Have all requested bytes been read?
-               assert(strlen($data) == $this->headerSize);
+               assert(strlen($data) == $this->getHeaderSize());
                //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
 
                // Last character must be the separator
@@ -232,9 +104,9 @@ class BaseFileStack extends BaseStacker {
                /*
                 * Now split it:
                 *
-                * 0 => Magic
-                * 1 => Total entries
-                * 2 => Current seek position
+                * 0 => magic
+                * 1 => total entries
+                * 2 => current seek position
                 */
                $this->header = explode(chr(self::SEPARATOR_HEADER_DATA), $data);
 
@@ -260,82 +132,6 @@ class BaseFileStack extends BaseStacker {
                //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
        }
 
-       /**
-        * Checks whether the file header is initialized
-        *
-        * @return      $isInitialized  Whether the file header is initialized
-        */
-       private function isFileHeaderInitialized () {
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
-               // Default is not initialized
-               $isInitialized = FALSE;
-
-               // Is the file initialized?
-               if ($this->isFileInitialized()) {
-                       // Some bytes has been written, so rewind to start of it.
-                       $rewindStatus = $this->getIteratorInstance()->rewind();
-                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] rewindStatus=%s', __METHOD__, __LINE__, $rewindStatus));
-
-                       // Is the rewind() call successfull?
-                       if ($rewindStatus != 1) {
-                               // Something bad happened
-                               self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Could not rewind().', __METHOD__, __LINE__));
-                       } // END - if
-
-                       // Read file header
-                       $this->readFileHeader();
-
-                       // The above method does already check the header
-                       $isInitialized = TRUE;
-               } // END - if
-
-               // Return result
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] isInitialized=%d - EXIT!', __METHOD__, __LINE__, intval($isInitialized)));
-               return $isInitialized;
-       }
-
-       /**
-        * Checks whether the file-based stack has been initialized
-        *
-        * @return      $isInitialized          Whether the file's size is zero
-        */
-       private function isFileInitialized () {
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
-
-               // Get it from iterator which holds the pointer instance. If FALSE is returned
-               $fileSize = $this->getIteratorInstance()->size();
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] fileSize=%s', __METHOD__, __LINE__, $fileSize));
-
-               /*
-                * The returned file size should not be FALSE or NULL as this means
-                * that the pointer class does not work correctly.
-                */
-               assert(is_int($fileSize));
-
-               // Is more than 0 returned?
-               $isInitialized = ($fileSize > 0);
-
-               // Return result
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] isInitialized=%d - EXIT!', __METHOD__, __LINE__, intval($isInitialized)));
-               return $isInitialized;
-       }
-
-       /**
-        * Creates the file-stack's header
-        *
-        * @return      void
-        */
-       private function createFileHeader () {
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
-               // The file's header should not be initialized here
-               assert(!$this->isFileHeaderInitialized());
-
-               // Simple flush file header which will create it.
-               $this->flushFileHeader();
-
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!!', __METHOD__, __LINE__));
-       }
-
        /**
         * Flushes the file header
         *
@@ -371,62 +167,6 @@ class BaseFileStack extends BaseStacker {
                //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
        }
 
-       /**
-        * Writes data at given position
-        *
-        * @param       $seekPosition   Seek position
-        * @param       $data                   Data to be written
-        * @return      void
-        */
-       private function writeData ($seekPosition, $data) {
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] seekPosition=%s,data()=%s - CALLED!', __METHOD__, __LINE__, $seekPosition, strlen($data)));
-
-               // Write data at given position
-               $this->getIteratorInstance()->writeAtPosition($seekPosition, $data);
-
-               // Update seek position
-               $this->updateSeekPosition();
-
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
-       }
-
-       /**
-        * Pre-allocates file (if enabled) with some space for later faster write access.
-        *
-        * @return      void
-        */
-       private function preAllocateFile () {
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
-
-               // Is it enabled?
-               if ($this->getConfigInstance()->getConfigEntry('file_stack_pre_allocate_enabled') != 'Y') {
-                       // Not enabled
-                       self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Not pre-allocating stack file.', __METHOD__, __LINE__));
-
-                       // Don't continue here.
-                       return;
-               } // END - if
-
-               // Message to user
-               self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Pre-allocating stack file ...', __METHOD__, __LINE__));
-
-               /*
-                * Calculate minimum length for one entry:
-                * minimum length = hash length + separator + name + minimum entry size = ?? + 1 + 10 + 1 = ??
-                */
-               $minLengthEntry = self::getHashLength() + strlen(self::SEPARATOR_HASH_NAME) + self::LENGTH_NAME + 1;
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] minLengthEntry=%s', __METHOD__, __LINE__, $minLengthEntry));
-
-               // Calulcate seek position
-               $seekPosition = $minLengthEntry * $this->getConfigInstance()->getConfigEntry('file_stack_pre_allocate_count');
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] seekPosition=%s', __METHOD__, __LINE__, $seekPosition));
-
-               // Now simply write a NUL there. This will pre-allocate the file.
-               $this->writeData($seekPosition, chr(0));
-
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
-       }
-
        /**
         * Analyzes entries in stack file. This will count all found (and valid)
         * entries, mark invalid as damaged and count gaps ("fragmentation"). If
@@ -434,7 +174,7 @@ class BaseFileStack extends BaseStacker {
         *
         * @return      void
         */
-       private function analyzeStackFile () {
+       private function analyzeFile () {
                //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
 
                // Make sure the file is initialized
@@ -475,14 +215,14 @@ class BaseFileStack extends BaseStacker {
                        $this->createFileHeader();
 
                        // And pre-allocate a bit
-                       $this->preAllocateFile();
+                       $this->preAllocateFile('file_stack');
                } // END - if
 
                // Load the file header
                $this->readFileHeader();
 
                // Count all entries in file
-               $this->analyzeStackFile();
+               $this->analyzeFile();
 
                /*
                 * Get stack index instance. This can be used for faster