改进的PHP文本数据库类

数据|数据库

找了些时间,改进了自己文本数据库系统,从空间利用效率和并发性能两个方面着手,搞高了程序性能。

在空间利用率上,做了两点改进,一是在删除记录的时候,如果记录的存放位置在数据库的末端,就自动修改数据库末端指针,而不是将此记录的空间作为一个闲置块存入闲置块记录中,这样就可以继续在数据文件尾分配任意长度的空间而不是像以前那样将这个删除记录的空间整块分配给下一次请求空间的新记录;第二点改进是在从闲置块中请求空间的时候,不仅继续采用原来的最佳适应法,而且在请求到合适的闲置块的时候并不是将整个块而是将其部分划分给新记录,这样又进一部提高了空间的利用率。

在并发性能上,增加了数据库的打开模式这个选项。为了保持文本数据库操作的原子性,以前都以写模式打开数据库,用户无论是从数据库中读数据或写数据,系统都会锁定数据库而禁止其它用户并发的读写操作,而大多情况下,用户都是浏览网页而不是POST数据,禁止对数据库的并行的读操作,势必成为网页浏览速度的瓶颈,为了加速网页生成速度,在数据库中加入了打开模式这一选项,在只读模式下,可以允许不同的用户并发地从数据库中申请数据,使得网页并发性能得到了一定程序上的提高。

下面给出新文本数据库类的部分代码,其相关注释可以从原来的文章:http://202.113.13.169/site/redboy/index.php?item=read&id=1&blogID=4中获得。

源代码:

<?
class TxtDB
{
    var $name='';//文本数据库名
    var $path='';
    var $minLen=20;
    var $isError;
    var $dbh;
    var $indxh;
    var $lfth;
    var $lckh;
    var $rcdCnt=0;
    var $maxID=0;
    var $leftCnt=0;
    var $DBend=0;
    var $mod='w';

    function TxtDB($name,$mod='w',$path='bpns_dbm')
    {
        $this->name=$name;
        $this->path=$path.'/'.$name;
        $this->isError=0;
        $this->mod=$mod;
        $path=$this->path;
        if ($name!='')
        {
            @mkdir($this->path,0777);
            if (!file_exists($path.'/'.$name.'.tdb')) $this->dbh=fopen($this->path.'/'.$name.'.tdb','w+');
            else $this->dbh=fopen($path.'/'.$name.'.tdb','r+');
            if (!file_exists($path.'/'.$name.'.indx')) $this->indxh=fopen($this->path.'/'.$name.'.indx','w+');
            else $this->indxh=fopen($path.'/'.$name.'.indx','r+');
            if (!file_exists($path.'/'.$name.'.lft')) $this->lfth=fopen($this->path.'/'.$name.'.lft','w+');
            else $this->lfth=fopen($this->path.'/'.$name.'.lft','r+');
            if ($this->mod=='w')
            {
                 $this->lckh=fopen($this->path.'/'.$name.'.lck','w');
                 flock($this->lckh,2);
                 fwrite($this->lckh,'lck');//lock the datebase
            }
            $rcd=$this->getRcd(0);
            $this->rcdCnt=$rcd[id];
            $this->maxID=$rcd[loc];
            $this->DBend=$rcd[len];
            $rcd=$this->getLeft(0);
            $this->leftCnt=$rcd[loc];
        }
        else $this->isError=1;
    }

    function setRcd($rid,$id,$loc,$len)
    {
        fseek($this->indxh,$rid*12);
        $str=pack('III',$id,$loc,$len);
        fwrite($this->indxh,$str,12);
    }

    function getRcd($rid)
    {
        fseek($this->indxh,$rid*12);
        $str=fread($this->indxh,12);
        $rcd=array();
        $rcd[id]=str2int($str);
        $rcd[loc]=str2int(substr($str,4,4));
        $rcd[len]=str2int(substr($str,8,4));
        return $rcd;
    }

    function setLeft($lid,$loc,$len)
    {
        fseek($this->lfth,$lid*8);
        $str=pack('II',$loc,$len);
        fwrite($this->lfth,$str,8);
    }

    function getLeft($lid)
    {
        fseek($this->lfth,$lid*8);
        $str=fread($this->lfth,8);
        $rcd[loc]=str2int($str);
        $rcd[len]=str2int(substr($str,4,4));
        return $rcd;
    }

    function clear()
    {
        $this->setRcd(0,0,0,0);
        $this->setLeft(0,0,0);
    }

    function close()
    {
        @fclose($this->dbh);
        @fclose($this->indxh);
        @fclose($this->lfth);
        @fclose($this->lckh);
    }

    function seekSpace($len)
    {
        $res=array('loc'=>0,'len'=>0);
        if ($this->leftCnt<1) return $res;
        $find=0;
        $min=1000000;
        for ($i=$this->leftCnt;$i>0;$i--)
        {
            $res=$this->getLeft($i);
            if ($res[len]==$len) {$find=$i;break;}
            else if($res[len]>$len)
            {
                if ($res[len]-$len<$min)
                {
                    $min=$res[len]-$len;
                    $find=$i;
                }
            }
        }
        if ($find)
        {
            $res=$this->getLeft($find);
            if ($res[len]<2*$len)
            {
                fseek($this->lfth,($find+1)*8);
                $str=fread($this->lfth,($this->leftCnt-$find)*8);
                fseek($this->lfth,$find*8);
                fwrite($this->lfth,$str);
                $this->leftCnt--;
                $this->setLeft(0,$this->leftCnt,0);
                return $res;
            }
            else
            {
                $rs=array();
                $rs[loc]=$res[loc];
                $rs[len]=$len;
                $res[loc]+=$len;
                $this->setLeft($find,$res[loc],$res[len]-$len);
                return $rs;
            }
        }
        else//fail
        {
            $res[len]=0;
            return $res;
        }
    }

    function insert($content,$len=0)//return with record id
    {
        $res=array('loc'=>0);
        if ($this->mod!='w') return 0;
        if (!$len) $len=strlen($content); 
        if ($len<$this->minLen) $len=$this->minLen;
        if ($this->leftCnt) $res=$this->seekSpace($len);
        if (!$res[len])
        {
            $res[loc]=$this->DBend;
            $res[len]=$len;
        }
        if ($res[loc]+$res[len]>$this->DBend) $this->DBend=$res[loc]+$res[len];
        //echo $this->DBend.'<br>';
        $this->maxID++;
        $this->rcdCnt++;
        $this->setRcd(0,$this->rcdCnt,$this->maxID,$this->DBend);
        $this->setRcd($this->rcdCnt,$this->maxID,$res[loc],$res[len]);
        fseek($this->dbh,$res[loc]);
        fwrite($this->dbh,$content,$len);
        return $this->maxID;
    }

    function findByID($id)
    {
        if ($id<1 or $id>$this->maxID or $this->rcdCnt<1) return 0;
        $left=1;
        $right=$this->rcdCnt;
        while($left<$right)
        {
            $mid=(int)(($left+$right)/2);
            if ($mid==$left or $mid==$right) break;
            $rcd=$this->getRcd($mid);
            if ($rcd[id]==$id) return $mid;
            else if($id<$rcd[id]) $right=$mid;
            else $left=$mid;
        }
        //$rcd=$this->getRcd($mid);
        //if ($rcd[id]==$id) return $mid;
        $rcd=$this->getRcd($left);
        if ($rcd[id]==$id) return $left;
        $rcd=$this->getRcd($right);
        if ($rcd[id]==$id) return $right;
        return 0;
    }

    function delete($id)
    {
        if ($this->mod!='w') return 0;
        $rid=$this->findByID($id);
        if (!$rid) return;
        $res=$this->getRcd($rid);
        fseek($this->indxh,($rid+1)*12);
        $str=fread($this->indxh,($this->rcdCnt-$i)*12);
        fseek($this->indxh,$rid*12);
        fwrite($this->indxh,$str);
        $this->rcdCnt--;
        if ($res[loc]+$res[len]==$this->DBend)
        {
            $this->DBend=$res[loc];
            $this->setRcd(0,$this->rcdCnt,$this->maxID,$this->DBend);
        }
        else
        {
            $this->setRcd(0,$this->rcdCnt,$this->maxID,$this->DBend);
            $this->leftCnt++;
            $this->setLeft(0,$this->leftCnt,0);
            $this->setLeft($this->leftCnt,$res[loc],$res[len]);
        }
    }

    function update($id,$newcontent,$len=0)
    {
        if ($this->mod!='w') return;
        $rid=$this->findByID($id);
        if (!$rid) return;
        if (!$len) $len=strlen($newcontent); 
        $rcd=$this->getRcd($rid);
        if ($rcd[len]<$len)
        {
            $this->leftCnt++;
            $this->setLeft(0,$this->leftCnt,0);
            $this->setLeft($this->leftCnt,$rcd[loc],$rcd[len]);
            $rcd[loc]=$this->DBend;
            $rcd[len]=$len;
            $this->DBend+=$len;
            $this->setRcd(0,$this->rcdCnt,$this->maxID,$this->DBend);
            $this->setRcd($rid,$rcd[id],$rcd[loc],$rcd[len]);
        }
        fseek($this->dbh,$rcd[loc]);
        fwrite($this->dbh,$newcontent,$len);
        //echo $id.'<br>'.$content.'<br>'.$len;
    }

    function selectByRid($rid)
    {
        $res=array('id'=>0,'content'=>'');
        if ($rid<1 or $rid>$this->rcdCnt) return $res;
        else $rcd=$this->getRcd($rid);
        $res[id]=$rcd[id];
        $res[len]=$rcd[len];
        fseek($this->dbh,$rcd[loc]);
        $res[content]=fread($this->dbh,$rcd[len]);
        //$res[rid]=$rid;
        return $res;
    }

    function select($id)
    {
        return $this->selectByRid($this->findByID($id));
    }

    function backup()
    {
        copy($this->path.'/'.$this->name.'.tdb',$this->path.'/'.$this->name.'.tdb.bck');
        copy($this->path.'/'.$this->name.'.indx',$this->path.'/'.$this->name.'.indx.bck');
        copy($this->path.'/'.$this->name.'.lft',$this->path.'/'.$this->name.'.lft.bck');
    }

    function recover()
    {
        copy($this->path.'/'.$this->name.'.tdb.bck',$this->path.'/'.$this->name.'.tdb');
        copy($this->path.'/'.$this->name.'.indx.bck',$this->path.'/'.$this->name.'.indx');
        copy($this->path.'/'.$this->name.'.lft.bck',$this->path.'/'.$this->name.'.lft');
    }
}

?>

 

PS: 其他可以参考上一篇文章:http://blog.csdn.net/heiyeshuwu/archive/2006/06/16/804265.aspx

 

 

时间: 2024-10-18 05:11:10

改进的PHP文本数据库类的相关文章

PHP文本数据库类及其基础上的文章系统

数据|数据库 一 文本数据库类目标 文本数据库设计的目标,是实现文本等数据的组织和存取,屏蔽数据存放的具体细节,向用户提供一个简单方便的文本数据的插入,修改,删除,查询的接口. 二 文本数据库思路 我们打算将相关的文本数据存放在同一个文件中,并以记录为单位实现对文本数据的组织与管理.记录可分为两中:定长记录和不定找记录.对于定长记录,我们可以用顺序存放的方式组织记录,这样对于第N个记录,我们可以直接以N*RceLength定位它在文件中的存放位置,对于读取,插入,更新操作来说,顺序存入的组织方式

改进后的日志类CLogger

在原有的基础上增加了module_name,表示模块名,当一个系统由多模块组成时,输出的日志将更加清晰,使用方法,以MOOON-agent中的为例: /** 不要修改下面的常量值,而应当通过对应的方法去修改 * 这些常量值主要是方便多模块共享,故放在这个公有头文件当中 */enum{ LOG_LINE_SIZE_MIN = 256, /** 日志行最小长度 */ LOG_LINE_SIZE_MAX = 32768, /** 日志行最大长度(32K) ,最大不能超过64K,因为使用2字节无符号整数

某文本数据库blog作者写的文本数据库操作类,很不错

数据|数据库 作者的1.0版: <? /* 本代码开源,您可以对其进行修改. 下面文字请不要修改. ********************************************* php文本数据库类1.0版 powerd by bpns mysite:http://space.tju.cn/site/redboy/ 2006-4-20 ********************************************* 为了您的数据库安全,请在此程序中更改您的数据默认目录 将f

SQL Server MFC DAO类和MFC ODBC类

大多数 mfc 开发人员都熟悉开放式数据库连接 (odbc) 数据库类 - 它们早在三年半以前就出现了.在 mfc 4.2 中,对这些类有一些重要的改进. 身为 c++ 开发人员,您可能不熟悉 dao,因为到目前为止它还只可用于 microsoft access 和 visual basic 程序设计系统.如果您熟悉 dao,就必须了解:dao 在 mfc 中的实现颇有不同,但包罗广泛. 了解 mfc odbc 类的开发人员必须知道:虽然 mfc dao 类比 odbc 类功能性更强,但 dao

《Java 2D游戏编程入门》—— 2.2 键盘改进

2.2 键盘改进 尽管键盘输入类允许在游戏循环中访问键盘状态,但是实现起来还是有一些问题.首先,游戏循环代码执行的时候,如果键盘按键没有按下,将会错过keypress事件.尽管对于这些简单的示例来说,不太可能发生这种情况,但当应用程序变得更强大并且游戏循环需要更多的时间来处理代码时,游戏循环就可能变得太慢而导致错过了输入.现在,只需要知道这可能是一个问题就行了.我们将会在第11章中讨论确保事件不会被错过的一种解决方案. 第二个问题是,当按键第一次被按下的时候,很难进行测试.如果需要跟踪20个按键

艾伟_转载:VS 2010 和 .NET 4.0 系列之《ASP.NET 4 中的SEO改进 》篇

本系列文章导航 VS 2010 和 .NET 4.0 系列之<ASP.NET 4 中的SEO改进 >篇 VS 2010 和 .NET 4.0 系列之<干净的Web.Config文件 >篇 VS 2010 和 .NET 4.0 系列之<起始项目模板>篇 VS 2010 和 .NET 4.0 系列之<多定向支持>篇 VS 2010 和 .NET 4.0 系列之<多显示器支持>篇 VS 2010 和 .NET 4.0 系列之<代码优化的Web开发

VS 2010 和 .NET 4.0 系列之《ASP.NET 4 中的SEO改进 》篇

本系列文章导航 VS 2010 和 .NET 4.0 系列之<ASP.NET 4 中的SEO改进 >篇 VS 2010 和 .NET 4.0 系列之<干净的Web.Config文件 >篇 VS 2010 和 .NET 4.0 系列之<起始项目模板>篇 VS 2010 和 .NET 4.0 系列之<多定向支持>篇 VS 2010 和 .NET 4.0 系列之<多显示器支持>篇 VS 2010 和 .NET 4.0 系列之<代码优化的Web开发

ASP.NET 4进行SEO优化提高网站排名和权重

ASP.NET 4包括了一系列新的运行时特性,可以帮助你进一步优化你的网站.其中一些新特性可以用来进行SEO优化以提高网站在搜索引擎中的排名和权重,这些特性包括: 新的Page.MetaKeywords 和 Page.MetaDescription 属性 针对ASP.NET Web Forms的新URL导向支持 新的Response.RedirectPermanent() 方法 下面是如何利用这些特性来进一步提高搜索引擎相关性的细节. Page.MetaKeywords 和 Page.MetaD

Java Web 框架的“甜点”

web 这是一篇很有趣的文档,所以摘要一下,其实类似阅读笔记,好像是3/25发布的:不知怎么翻译Sweet Spots,难道翻译为甜处.甜头.蜜点.蜜穴? 本文基于对以下人的采访(最后两位的看法独到还是自己看吧!):JSF             Jacob HookomRIFE            Geert BevinSeam            Gavin KingSpring MVC      Rob HarropSpring Web Flow Rob Harrop and Keit