add #memorySearch interface for purge memory search

This commit is contained in:
lionsoul 2016-06-30 16:04:02 +08:00
parent 32ad842926
commit e436094563
3 changed files with 107 additions and 13 deletions

View File

@ -30,6 +30,13 @@ class Ip2Region
private $lastIndexPtr = 0;
private $totalBlocks = 0;
/**
* for memory mode only
* the original db binary string
*/
private $dbBinStr = NULL;
private $dbFile = NULL;
/**
* construct method
*
@ -37,7 +44,66 @@ class Ip2Region
*/
public function __construct( $ip2regionFile )
{
$this->dbFileHandler = fopen($ip2regionFile, 'r');
$this->dbFile = $ip2regionFile;
}
/**
* all the db binary string will be loaded into memory
* then search the memory only and this will a lot faster than disk base search
* @Note:
* invoke it once before put it to public invoke could make it thread safe
*
* @param $ip
*/
public function memorySearch($ip)
{
//check and load the binary string for the first time
if ( $this->dbBinStr == NULL ) {
$this->dbBinStr = file_get_contents($this->dbFile);
if ( $this->dbBinStr == false ) {
throw new Exception("Fail to open the db file {$this->dbFile}");
}
$this->firstIndexPtr = self::getLong($this->dbBinStr, 0);
$this->lastIndexPtr = self::getLong($this->dbBinStr, 4);
$this->totalBlocks = ($this->lastIndexPtr-$this->firstIndexPtr)/INDEX_BLOCK_LENGTH + 1;
echo "length: ", strlen($this->dbBinStr);
}
if ( is_string($ip) ) $ip = ip2long($ip);
//binary search to define the data
$l = 0;
$h = $this->totalBlocks;
$dataPtr = 0;
while ( $l <= $h ) {
$m = (($l + $h) >> 1);
$p = $this->firstIndexPtr + $m * INDEX_BLOCK_LENGTH;
$sip = self::getLong($this->dbBinStr, $p);
if ( $ip < $sip ) {
$h = $m - 1;
} else {
$eip = self::getLong($this->dbBinStr, $p + 4);
if ( $ip > $eip ) {
$l = $m + 1;
} else {
$dataPtr = self::getLong($this->dbBinStr, $p + 8);
break;
}
}
}
//not matched just stop it here
if ( $dataPtr == 0 ) return NULL;
//get the data
$dataLen = (($dataPtr >> 24) & 0xFF);
$dataPtr = ($dataPtr & 0x00FFFFFF);
return array(
'city_id' => self::getLong($this->dbBinStr, $dataPtr),
'region' => substr($this->dbBinStr, $dataPtr + 4, $dataLen - 4)
);
}
/**
@ -51,6 +117,14 @@ class Ip2Region
//check and conver the ip address
if ( is_string($ip) ) $ip = ip2long($ip);
if ( $this->totalBlocks == 0 ) {
//check and open the original db file
if ( $this->dbFileHandler == NULL ) {
$this->dbFileHandler = fopen($this->dbFile, 'r');
if ( $this->dbFileHandler == false ) {
throw new Exception("Fail to open the db file {$this->dbFile}");
}
}
fseek($this->dbFileHandler, 0);
$superBlock = fread($this->dbFileHandler, 8);
@ -102,6 +176,7 @@ class Ip2Region
/**
* get the data block associated with the specifield ip with b-tree search algorithm
* @Note: not thread safe
*
* @param ip
* @return Mixed Array for NULL for any error
@ -112,6 +187,14 @@ class Ip2Region
//check and load the header
if ( $this->HeaderSip == NULL ) {
//check and open the original db file
if ( $this->dbFileHandler == NULL ) {
$this->dbFileHandler = fopen($this->dbFile, 'r');
if ( $this->dbFileHandler == false ) {
throw new Exception("Fail to open the db file {$this->dbFile}");
}
}
fseek($this->dbFileHandler, 8);
$buffer = fread($this->dbFileHandler, TOTAL_HEADER_LENGTH);
@ -240,7 +323,11 @@ class Ip2Region
*/
public function __destruct()
{
if ( $this->dbFileHandler != NULL ) fclose($this->dbFileHandler);
if ( $this->dbFileHandler != NULL ) {
fclose($this->dbFileHandler);
}
$this->dbBinStr = NULL;
$this->HeaderSip = NULL;
$this->HeaderPtr = NULL;
}

View File

@ -15,12 +15,19 @@ EOF;
array_shift($argv);
$dbFile = $argv[0];
$method = 1;
$method = 'btreeSearch';
$algorithm = 'B-tree';
if ( isset($argv[1])
&& strtolower($argv[1]) == 'binary' ) {
$method = 2;
if ( isset($argv[1]) ) {
switch ( strtolower($argv[1]) ) {
case 'binary':
$algorithm = 'Binary';
$method = 'binarySearch';
break;
case 'memory':
$algorithm = 'Memory';
$method = 'memorySearch';
break;
}
}
require dirname(__FILE__) . '/Ip2Region.class.php';
@ -47,7 +54,7 @@ while ( true ) {
}
$s_time = getTime();
$data = $method==2 ? $ip2regionObj->binarySearch($line) : $ip2regionObj->btreeSearch($line);
$data = $ip2regionObj->{$method}($line);
$c_time = getTime() - $s_time;
printf("%s|%s in %.5f millseconds\n", $data['city_id'], $data['region'], $c_time);
}

Binary file not shown.