From f3c85a21e5257627501594f14304492822f3b499 Mon Sep 17 00:00:00 2001 From: Michael Meckelein Date: Mon, 10 Mar 2008 17:30:48 +0100 Subject: [PATCH 1/2] modified: classes/logstreamdisk.class.php - some read modification including changing direction - also some performance tuning - not yet ready! This version does not work at all modified: include/constants_errors.php --- classes/logstreamdisk.class.php | 201 +++++++++++++++++++++++++++----- include/constants_errors.php | 4 +- 2 files changed, 177 insertions(+), 28 deletions(-) diff --git a/classes/logstreamdisk.class.php b/classes/logstreamdisk.class.php index d0c1f34..1fd5532 100644 --- a/classes/logstreamdisk.class.php +++ b/classes/logstreamdisk.class.php @@ -19,6 +19,15 @@ if ( !defined('IN_PHPLOGCON') ) class LogStreamDisk extends LogStream { private $_currentOffset = -1; private $_fp = null; + private $_bEOF = false; + + const _BUFFER_LENGHT = 4096; + private $_buffer = false; + private $_p_buffer = -1; + + // cache for backwards reading + private $_cache_lines = null; + private $_p_cache_lines = -1; // Constructor public function LogStreamDisk($streamConfigObj) { @@ -29,15 +38,19 @@ class LogStreamDisk extends LogStream { * Open the file with read access. * * @param streamConfigObj object in: It has to be a LogSteamDiskConfig object. + * @param bStartAtEOF bool in: If set to true the file pointer is set at EOF. * @return integer Error stat */ - public function Open($arrProperties) { + public function Open($arrProperties, $bStartAtEOF = false) { if(!file_exists($this->_logStreamConfigObj->FileName)) { return ERROR_FILE_NOT_FOUND; } - $this->_fp = fopen($this->_logStreamConfigObj->FileName, 'r'); - $this->_currentOffset = 0; + $this->_fp = fopen($this->_logStreamConfigObj->FileName, 'r'); + if ($bStartAtEOF) { + fseek($this->_fp, 0, SEEK_END); + } + $this->_currentOffset = ftell($this->_fp); $this->_arrProperties = $arrProperties; return SUCCESS; } @@ -55,7 +68,39 @@ class LogStreamDisk extends LogStream { return SUCCESS; } - + public function ReadNextBlock() { + echo 'in ReadNextBlock
'; + $this->_buffer = fread($this->_fp, self::_BUFFER_LENGHT); + $this->_p_buffer = 0; + + if ($this->_buffer == false) + return ERROR_FILE_BOF; + + return SUCCESS; + } + + /** + * Read the data from a specific uID which means in this + * case from a given offset of the file. + * + * @param uID integer in/out: unique id of the data row + * @param logLine string out: data row + * @return integer Error state + * @see ReadNext() + */ + public function Read($uID, &$logLine) { + fseek($this->_fp, $uI); + + // with Read we can only read forwards. + // so we have to remember the current read + // direction + $tmp = $this->_readDirection; + $iRet = $this->ReadNext($uID, $logLine); + $this->_readDirection = $tmp; + + return $iRet; + } + /** * Read the next line from the file depending on the current * read direction. @@ -70,13 +115,66 @@ class LogStreamDisk extends LogStream { * @see ReadNext */ public function ReadNext(&$uID, &$logLine) { + if ($this->_readDirection == EnumReadDirection::Forward) { + return $this->ReadNextForwards($uID, $logLine); + } - $uID = $this->_currentOffset; + return $this->ReadNextBackwards($uID, $logLine); + } + private function ReadNextForwards(&$uID, &$logLine) { + if ($this->bEOF) { + return ERROR_FILE_BOF; + } + + if (($this->_p_buffer == sizeof($this->_buffer)) && ($this->ReadNextBlock() != SUCCESS)) { + return ERROR_UNDEFINED; + } + + $line = ''; + do { + $pos = $this->_p_buffer; + do { + $ch = $this->_buffer[$pos]; + switch ($ch) { + case '\r': + case '\n': + $startPosOfLine = $this->_currentOffset - sizeof($line); + $this->_p_buffer = $pos + 1; + $this->_currentOffset++; + if ((($ch == '\r') && (($this->_p_buffer < sizeof($this->_buffer)) || ($this->ReadNextBlock() != SUCCESS))) && ($this->_p_buffer[$this->_p_buffer] == '\n')) { + $this->_p_buffer++; + $this->_currentOffset++; + } + // here a new line starts + $uID = $startPosOfLine; + $logLine = $line; + return SUCCESS; + + case '\0': + $this->bEOF = true; + $uID = $this->_currentOffset - sizeof($line); + $logLine = $line; + return SUCCESS; + } + $line .= $ch; + $pos++; + $this->_currentOffset++; + } while ($pos < sizeof($this->_buffer)); + } while ($this->ReadNextBlock() == SUCCESS); + + return ERROR_UNDEFINED; + } + +/* + private function ReadNextForwards(&$uID, &$logLine) { + if (feof($this->_fp)) { return ERROR_FILE_EOF; } + $uID = ftell($this->_fp); + $logLine = fgets($this->_fp); if ($logLine === false) { // ToDo: error occurs, or EOF @@ -85,30 +183,71 @@ class LogStreamDisk extends LogStream { $this->_currentOffset = $this->_currentOffset + sizeof($logLine); - return 0; + return SUCCESS; + } +*/ + + private function ReadNextBackwards(&$uID, &$logLine) { + if ($this->_p_cache_lines < 0) { + if (($iRet = $this->InitCacheLines()) > 0) { // error or BOF? + return $iRet; + } + } + + // at this stage we can read from cache + $uID = $this->_cache_lines[$this->_p_cache_lines][0]; + $logLine = $this->_cache_lines[$this->_p_cache_lines][1]; + $this->_p_cache_lines--; + + return SUCCESS; } - /** - * Read the data from a specific uID which means in this - * case from a given offset of the file. - * - * @param uID integer in/out: unique id of the data row - * @param logLine string out: data row - * @return integer Error state - * @see ReadNext() - */ - public function Read($uID, &$logLine) { - $this->_currentOffset = $uID; - fseek($fp, $this->_currentOffset); + private function ClearCacheLines() { + unset($this->_cache_lines); + $this->_p_cache_lines = -1; + } - // with Read we can only read forwards. - // so we have to remember the current read - // direction - $tmp = $this->_readDirection; - $iRet = $this->ReadNext($uID, $logLine); - $this->_readDirection = $tmp; + private function InitCacheLines() { + $orig_offset = ftell($this->_fp); + if ($this->_readDirection == EnumReadDirection::Backward) { + // if we have already used the cache take the last positon + // as offset and then clear the cache + if (isset($this->_cache_lines[0][0])) { + $orig_offset = $this->_cache_lines[0][0]; + $this->ClearCacheLines(); - return $iRet; + // check if it is the first line so we have BOF + if ($orig_offset == 0) { + return ERROR_FILE_BOF; + } + } + } + + $offset = $orig_offset - 4096; + if ($offset < 0) { + $offset = 0; + } + + fseek($this->_fp, $offset); + + if ($offset != 0) { + // we do not know if we are on the beginning of a line + // therefore we simply skip the first line + fgets($this->_fp); + } + + while (($offset = ftell($this->_fp)) < $orig_offset) { + $this->_p_cache_lines++; + $this->_cache_lines[$this->_p_cache_lines][0] = $offset; + $this->_cache_lines[$this->_p_cache_lines][1] = fgets($this->_fp); + if ($this->_cache_lines[$this->_p_cache_line][1] === false) { + // probably EOF or an error + unset($this->_cache_lines[$this->_p_cache_line]); + $this->_p_cache_lines--; + break; + } + } + return SUCCESS; } /** @@ -118,17 +257,25 @@ class LogStreamDisk extends LogStream { * @return integer Error state */ public function SetFilter($filter) { - return 0; + return SUCCESS; } /** * Set the direction the stream should read data. * + * + * * @param enumReadDirectionfilter EnumReadDirection in: The new direction. * @return integer Error state */ public function SetReadDirection($enumReadDirection) { - return 0; + + // only if the read direction change we have do do anything + if ($this->_readDirection == $enumReadDirection) + return SUCCESS; + + $this->_readDirection = $enumReadDirection; + return SUCCESS; } } diff --git a/include/constants_errors.php b/include/constants_errors.php index 1f9f933..75f907b 100644 --- a/include/constants_errors.php +++ b/include/constants_errors.php @@ -2,5 +2,7 @@ define('SUCCESS ', 0); define('ERROR_FILE_NOT_FOUND', 1); define('ERROR_FILE_CANT_CLOSE', 2); -define('ERROR_FILE_EOF', 2); +define('ERROR_FILE_EOF', 3); +define('ERROR_FILE_BOF', 4); +define('ERROR_UNDEFINED', 5); ?> \ No newline at end of file From a15b0c57f5e144b6dd94ddf932a16fa08b3c0da7 Mon Sep 17 00:00:00 2001 From: Michael Meckelein Date: Tue, 11 Mar 2008 11:34:07 +0100 Subject: [PATCH 2/2] modified: classes/logstreamdisk.class.php Improved reading from file using a buffer Backwards reading is not yet implemented --- classes/logstreamdisk.class.php | 56 ++++++++++++++------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/classes/logstreamdisk.class.php b/classes/logstreamdisk.class.php index 1fd5532..c70d6b8 100644 --- a/classes/logstreamdisk.class.php +++ b/classes/logstreamdisk.class.php @@ -18,11 +18,13 @@ if ( !defined('IN_PHPLOGCON') ) */ class LogStreamDisk extends LogStream { private $_currentOffset = -1; + private $_currentStartPos = -1; private $_fp = null; private $_bEOF = false; const _BUFFER_LENGHT = 4096; private $_buffer = false; + private $_buffer_lenght = -1; private $_p_buffer = -1; // cache for backwards reading @@ -45,13 +47,17 @@ class LogStreamDisk extends LogStream { if(!file_exists($this->_logStreamConfigObj->FileName)) { return ERROR_FILE_NOT_FOUND; } - + $this->_fp = fopen($this->_logStreamConfigObj->FileName, 'r'); if ($bStartAtEOF) { fseek($this->_fp, 0, SEEK_END); } $this->_currentOffset = ftell($this->_fp); + $this->_currentStartPos = $this->_currentOffset; $this->_arrProperties = $arrProperties; + + // init read + $this->ReadNextBlock(); return SUCCESS; } @@ -69,8 +75,9 @@ class LogStreamDisk extends LogStream { } public function ReadNextBlock() { - echo 'in ReadNextBlock
'; + //echo 'in ReadNextBlock
'; $this->_buffer = fread($this->_fp, self::_BUFFER_LENGHT); + $this->_buffer_lenght = strlen($this->_buffer); $this->_p_buffer = 0; if ($this->_buffer == false) @@ -124,43 +131,28 @@ class LogStreamDisk extends LogStream { private function ReadNextForwards(&$uID, &$logLine) { if ($this->bEOF) { - return ERROR_FILE_BOF; + return ERROR_FILE_EOF; } - if (($this->_p_buffer == sizeof($this->_buffer)) && ($this->ReadNextBlock() != SUCCESS)) { + if (($this->_p_buffer == $this->_buffer_lenght) && ($this->ReadNextBlock() != SUCCESS)) { return ERROR_UNDEFINED; } - + $line = ''; do { - $pos = $this->_p_buffer; - do { - $ch = $this->_buffer[$pos]; - switch ($ch) { - case '\r': - case '\n': - $startPosOfLine = $this->_currentOffset - sizeof($line); - $this->_p_buffer = $pos + 1; - $this->_currentOffset++; - if ((($ch == '\r') && (($this->_p_buffer < sizeof($this->_buffer)) || ($this->ReadNextBlock() != SUCCESS))) && ($this->_p_buffer[$this->_p_buffer] == '\n')) { - $this->_p_buffer++; - $this->_currentOffset++; - } - // here a new line starts - $uID = $startPosOfLine; - $logLine = $line; - return SUCCESS; - case '\0': - $this->bEOF = true; - $uID = $this->_currentOffset - sizeof($line); - $logLine = $line; - return SUCCESS; - } - $line .= $ch; - $pos++; - $this->_currentOffset++; - } while ($pos < sizeof($this->_buffer)); + $pos = -1; + if (($pos = strpos($this->_buffer, "\n", $this->_p_buffer)) !== false) { + $logLine = $line . substr($this->_buffer, $this->_p_buffer, $pos - $this->_p_buffer); + $this->_currentOffset = $pos - $this->_p_buffer + 1; + $this->_p_buffer = $pos + 1; + $uID = $this->_currentStartPos; + $this->_currentStartPos = $this->_currentOffset; + return SUCCESS; + } + + $line .= substr($this->_buffer, $this->_p_buffer, $this->_buffer_lenght - $this->_p_buffer); + $this->_currentOffset += $this->_buffer_lenght - $this->_p_buffer; } while ($this->ReadNextBlock() == SUCCESS); return ERROR_UNDEFINED;