7 Star 8 Fork 2

Gitee 极速下载/CuteDB

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/liexusong/CuteDB
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
CuteDB.php 15.09 KB
一键复制 编辑 原始数据 按行查看 历史
xusong.lie 提交于 2018-07-23 18:47 . update some codes
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
<?php
/**
* Tiny DataBase implements in PHP using HashTable algorithm
* @author: Liexusong <liexusong@qq.com>
*/
class CuteDB
{
const CUTEDB_ENTRIES = 1048576;
const CUTEDB_VERSION = 2;
const CUTEDB_HEADER_SIZE = 20;
const CUTEDB_LINK_OFFSET = 12;
private $_idxfile = null;
private $_datfile = null;
private $_headoff = 0;
private $_tailoff = 0;
private $_iterator = null;
private function initDB()
{
/**
* DB index file header:
* 4 bytes for "CUTE"
* 4 bytes for version
* 4 bytes for hash bucket entries
* 4 bytes for link list head
* 4 bytes for link list tail
*/
$header = pack('C4L4', 67, 85, 84, 69,
CuteDB::CUTEDB_VERSION,
CuteDB::CUTEDB_ENTRIES,
0, 0);
if (fwrite($this->_idxfile, $header) != CuteDB::CUTEDB_HEADER_SIZE) {
return false;
}
$block = pack('L128',
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
$blockSize = strlen($block);
$bucketSize = CuteDB::CUTEDB_ENTRIES * 4;
for ($i = 0; $i < $bucketSize; $i += $blockSize) {
if (fwrite($this->_idxfile, $block) != $blockSize) {
return false;
}
}
return true;
}
private function validateDB()
{
$header = fread($this->_idxfile, CuteDB::CUTEDB_HEADER_SIZE);
if (!$header || strlen($header) != CuteDB::CUTEDB_HEADER_SIZE) {
return false;
}
$sign = unpack('C4', substr($header, 0, 4));
if ($sign[1] != 67 || $sign[2] != 85 ||
$sign[3] != 84 || $sign[4] != 69)
{
return false;
}
$sign = unpack('L4', substr($header, 4));
if ($sign[1] != CuteDB::CUTEDB_VERSION ||
$sign[2] != CuteDB::CUTEDB_ENTRIES)
{
return false;
}
$this->_headoff = $sign[3];
$this->_tailoff = $sign[4];
$this->_iterator = $this->_headoff;
return true;
}
public function open($dbname)
{
if ($this->_idxfile) {
fclose($this->_idxfile);
}
if ($this->_datfile) {
fclose($this->_datfile);
}
$idxFileName = sprintf('%s.idx', $dbname);
$datFileName = sprintf('%s.dat', $dbname);
$init = false;
if (!file_exists($idxFileName)) {
$init = true;
$mode = 'w+b';
} else {
$mode = 'r+b';
}
$this->_idxfile = fopen($idxFileName, $mode);
$this->_datfile = fopen($datFileName, $mode);
if (!$this->_idxfile || !$this->_datfile) {
if ($this->_idxfile) {
fclose($this->_idxfile);
}
if ($this->_datfile) {
fclose($this->_datfile);
}
return false;
}
if ($init) {
return $this->initDB();
}
return $this->validateDB();
}
private function getIndexOffset($key)
{
$hash = crc32($key);
if ($hash < 0) { /* 32bit system may be return negative */
$hash = -$hash;
}
$index = $hash % CuteDB::CUTEDB_ENTRIES;
return CuteDB::CUTEDB_HEADER_SIZE + $index * 4;
}
private function unpackItem($item)
{
$package = unpack('L5', substr($item, 0, 20));
$offset = $package[1];
$preoff = $package[2];
$nexoff = $package[3];
$datoff = $package[4];
$datlen = $package[5];
$package = unpack('C2', substr($item, 20, 2));
$keylen = $package[1];
$delete = $package[2];
$keyval = substr($item, 22, $keylen);
return [
$offset,
$preoff,
$nexoff,
$datoff,
$datlen,
$delete,
$keyval,
];
}
private function packItem(
$offset, $preoff, $nexoff, $datoff,
$datlen, $keylen, $delete, $keyval
) {
$keyItem = pack('L5C2', $offset, $preoff, $nexoff,
$datoff, $datlen, $keylen, $delete);
$keyItem .= $keyval;
if (strlen($keyItem) > 128) {
return false;
}
if (strlen($keyItem) < 128) {
$zero = pack('x');
for ($i = 128 - strlen($keyItem); $i > 0; $i--) {
$keyItem .= $zero;
}
}
return $keyItem;
}
public function set($key, $value, $replace = false)
{
$indexoffset = $this->getIndexOffset($key);
if (fseek($this->_idxfile, $indexoffset, SEEK_SET) == -1) {
return false;
}
$item = fread($this->_idxfile, 4);
if (strlen($item) != 4) {
return false;
}
$headoffset = unpack('L', $item)[1];
$curroffset = 0;
$update = false;
$offset = $headoffset;
while ($offset) {
if (fseek($this->_idxfile, $offset, SEEK_SET) == -1) {
return false;
}
$curroffset = $offset;
$item = fread($this->_idxfile, 128);
if (strlen($item) != 128) {
return false;
}
$package = $this->unpackItem($item);
$offset = $package[0];
$preoff = $package[1];
$nexoff = $package[2];
$datoff = $package[3];
$datlen = $package[4];
$delete = $package[5];
$keyval = $package[6];
if ($keyval == $key) {
$update = true;
break;
}
}
if ($update && !$replace) {
return false;
}
/* store data and get offset */
if (!$update || $datlen < strlen($value)) {
if (fseek($this->_datfile, 0, SEEK_END) == -1) {
return false;
}
$datoff = ftell($this->_datfile);
} else {
if (fseek($this->_datfile, $datoff, SEEK_SET) == -1) {
return false;
}
}
$datlen = strlen($value);
if (fwrite($this->_datfile, $value) != $datlen) {
return false;
}
/* store key index and get offset */
if (!$update) {
$offset = $headoffset;
$preoff = $this->_tailoff;
$nexoff = 0;
}
$keylen = strlen($key);
$keyItem = $this->packItem($offset, $preoff, $nexoff,
$datoff, $datlen, $keylen, 0, $key);
if (!$keyItem) {
return false;
}
if (!$update) { /* new key */
$tailoff = $this->_tailoff; /* prev key offset */
if (fseek($this->_idxfile, 0, SEEK_END) == -1) {
return false;
}
$this->_tailoff = ftell($this->_idxfile);
if (!$this->_headoff) {
$this->_headoff = $this->_tailoff;
$this->_iterator = $this->_headoff;
}
if (fwrite($this->_idxfile, $keyItem) != 128) {
return false;
}
/* update bucket index */
if (fseek($this->_idxfile, $indexoffset, SEEK_SET) == -1) {
return false;
}
$lastoff = pack('L', $this->_tailoff);
if (fwrite($this->_idxfile, $lastoff) != 4) {
return false;
}
/* update link list */
if ($tailoff > 0) { /* update last node next pointer */
if (fseek($this->_idxfile, $tailoff, SEEK_SET) == -1) {
return false;
}
$item = fread($this->_idxfile, 128);
if (strlen($item) != 128) {
return false;
}
$package = $this->unpackItem($item);
$offset = $package[0];
$preoff = $package[1];
$nexoff = $package[2];
$datoff = $package[3];
$datlen = $package[4];
$delete = $package[5];
$keyval = $package[6];
$keylen = strlen($keyval);
$keyItem = $this->packItem($offset, $preoff, $this->_tailoff,
$datoff, $datlen, $keylen, $delete,
$keyval);
if (!$keyItem) {
return false;
}
if (fseek($this->_idxfile, $tailoff, SEEK_SET) == -1) {
return false;
}
if (fwrite($this->_idxfile, $keyItem) != 128) {
return false;
}
}
if (fseek($this->_idxfile, CuteDB::CUTEDB_LINK_OFFSET) == -1) {
return false;
}
$link = pack('L2', $this->_headoff, $this->_tailoff);
if (fwrite($this->_idxfile, $link) != 8) {
return false;
}
} else {
if (fseek($this->_idxfile, $curroffset, SEEK_SET) == -1) {
return false;
}
if (fwrite($this->_idxfile, $keyItem) != 128) {
return false;
}
}
return true;
}
public function get($key)
{
$indexoffset = $this->getIndexOffset($key);
if (fseek($this->_idxfile, $indexoffset, SEEK_SET) == -1) {
return false;
}
$item = fread($this->_idxfile, 4);
if (strlen($item) != 4) {
return false;
}
$found = false;
$datlen = 0;
$datoff = 0;
$delete = 0;
$offset = unpack('L', $item)[1];
while ($offset) {
if (fseek($this->_idxfile, $offset, SEEK_SET) == -1) {
return false;
}
$item = fread($this->_idxfile, 128);
if (strlen($item) != 128) {
return false;
}
$package = $this->unpackItem($item);
$offset = $package[0];
$preoff = $package[1];
$nexoff = $package[2];
$datoff = $package[3];
$datlen = $package[4];
$delete = $package[5];
$keyval = $package[6];
if ($keyval == $key) {
$found = true;
break;
}
}
if (!$found || $delete) {
return false;
}
if (fseek($this->_datfile, $datoff, SEEK_SET) == -1) {
return false;
}
return fread($this->_datfile, $datlen);
}
public function delete($key)
{
$indexoffset = $this->getIndexOffset($key);
if (fseek($this->_idxfile, $indexoffset, SEEK_SET) == -1) {
return false;
}
$item = fread($this->_idxfile, 4);
if (strlen($item) != 4) {
return false;
}
$headoffset = unpack('L', $item)[1];
$curroffset = 0;
$found = false;
$offset = $headoffset;
while ($offset) {
if (fseek($this->_idxfile, $offset, SEEK_SET) == -1) {
return false;
}
$curroffset = $offset;
$item = fread($this->_idxfile, 128);
if (strlen($item) != 128) {
return false;
}
$package = $this->unpackItem($item);
$offset = $package[0];
$preoff = $package[1];
$nexoff = $package[2];
$datoff = $package[3];
$datlen = $package[4];
$delete = $package[5];
$keyval = $package[6];
if ($keyval == $key) {
$found = true;
break;
}
}
if (!$found || $delete) {
return false;
}
$keylen = strlen($key);
$delete = 1;
$keyItem = $this->packItem($offset, $preoff, $nexoff, $datoff,
$datlen, $keylen, $delete, $key);
if (!$keyItem) {
return false;
}
if (fseek($this->_idxfile, $curroffset, SEEK_SET) == -1) {
return false;
}
if (fwrite($this->_idxfile, $keyItem) != 128) {
return false;
}
return true;
}
public function moveHead()
{
$this->_iterator = $this->_headoff;
}
public function moveTail()
{
$this->_iterator = $this->_tailoff;
}
public function next()
{
if (!$this->_iterator) {
return false;
}
if (fseek($this->_idxfile, $this->_iterator) == -1) {
return false;
}
$item = fread($this->_idxfile, 128);
if (strlen($item) != 128) {
return false;
}
$package = $this->unpackItem($item);
$offset = $package[0];
$preoff = $package[1];
$nexoff = $package[2];
$datoff = $package[3];
$datlen = $package[4];
$delete = $package[5];
$keyval = $package[6];
$this->_iterator = $nexoff;
if ($delete) {
return $this->next();
}
if (fseek($this->_datfile, $datoff) == -1) {
return false;
}
$datval = fread($this->_datfile, $datlen);
if (strlen($datval) != $datlen) {
return false;
}
return [$keyval, $datval];
}
public function prev()
{
if (!$this->_iterator) {
return false;
}
if (fseek($this->_idxfile, $this->_iterator) == -1) {
return false;
}
$item = fread($this->_idxfile, 128);
if (strlen($item) != 128) {
return false;
}
$package = $this->unpackItem($item);
$offset = $package[0];
$preoff = $package[1];
$nexoff = $package[2];
$datoff = $package[3];
$datlen = $package[4];
$delete = $package[5];
$keyval = $package[6];
$this->_iterator = $preoff;
if ($delete) {
return $this->next();
}
if (fseek($this->_datfile, $datoff) == -1) {
return false;
}
$datval = fread($this->_datfile, $datlen);
if (strlen($datval) != $datlen) {
return false;
}
return [$keyval, $datval];
}
public function flush()
{
fflush($this->_idxfile);
fflush($this->_datfile);
}
public function close()
{
if ($this->_idxfile) {
fclose($this->_idxfile);
}
if ($this->_datfile) {
fclose($this->_datfile);
}
$this->_idxfile = null;
$this->_datfile = null;
}
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
PHP
1
https://gitee.com/mirrors/CuteDB.git
git@gitee.com:mirrors/CuteDB.git
mirrors
CuteDB
CuteDB
master

搜索帮助