[转]解决 textdb 核心问题:超负载与稳定性

Ofstar------解决 textdb 核心问题:超负载与稳定性
原文地址:http://www.ofstar.net/read.php?fid=2&tid=92


先申明.以下内容完全由fenyu和王学集研究成果(希望我们的菲薄之力能给php---texdb带来新的理念).

下面主要讲解ofstar----textdb实现数据的负载能力.与稳定性的实现!
所有算法来源 ofstar board http://www.ofstar.net
时间问题.代码没有做详细的解释.如果您对其中的细节问题不解或是有好的建议.或可以联系ofstar 团队管理人王学集.QQ:280205859 .当然在大框架不变的前提下.我们以后还会继续在效率上下工夫.其中一些算法细节可能还有所变化!

(一)数据库模型
数据库是一种信息的集合,每个集合都包含一条或多条形式统一的记录,记录由字段构成.通常将集合称为表,将记录称为表中的行.
数据库一般分为:平面文件数据库(TEXT),层次化数据库,网络数据库,关系数据库(mysql),对象与对象关系型数据库!

关系型数据库是程序员开发软件的解放

由于平件文件数据库,必须直接与操作系统联系,当应用程序需要编辑这种信息时,必须确保字段与有正确的形式.这种形式的接口代价昂贵,因为她需要一种第3代语言(3GL),需要有掌握高度技能的人员进行长时间的开发!比如程序员必须考虑数据的

逻辑和物理表示,比如要从文件里读取一个整数,程序员需要知道它是写成文本形式还是二进制形式。数据在文件和应用程序之间流动时,必须遵循一定的约定。所以平面文件数据库程序的高效性一般取决于程序员的辛勤与水平!相对于MYSQL由于实现了数据的独立性,也实现了结构的独立性!因此程序员无须承受数据管理的负担!抛开了很多数据库处理的内部细节!这便是RDBMS产生最重要的理由!也是她普及的理由!

优秀的程序--对象关系数据库模型

数据库模型里,比如MYSQL是一种关系型数据库,但是关系模型并不是MYSQL的专利,数据库理论的革新正在继续,先进技术的一些基本原理也可以用于关系模型,如果你是精通3GL的程序员,使用平面文件数据库不仅可以开发出优秀的程序!而且在基层数据处理,编程控制,资源利用上,都有很大的优势! 如果需要对大量数据进行频繁的读写!,可以使用定位指针读取指定的数据,定长索引, 所谓的负载问题,迎刃而解,控制起来也非常灵活方便,层次化与网络模型的并发性原理都可以利用!当然最重要的还是程序员的敏觉性,设计完善的索引表,是置关重要的!

下面我将主要结合ofstar论坛程序讨论textdb--平面文件数据库在高负载下的稳定与快速.textdb的安全接口问题.整体效率的实现.数据检索等....

( 以下负载算法和稳定性算法归属Ofstar board.请务必尊重我们的劳动成果! )

(二)textdb高负载的前提实现数据的快速处理

(1)textdb传统不足:
有过开发经历的朋友一定有遇到.大数据量的操作简直就是噩梦.先不说大数据量下.操作数据的稳定性!单是那简单的添加删除以及修改所涉及的数据不得不让大部分的程序员望而却步....大量的数据处理与服务器并发性冲突造成的数据的不准确和不稳定现象.更是让广大用户抛弃甚至鄙视着textdb....
于是问题便产生了.如何解决对大量数据进行快速稳定地实现添加删除.修改等一系列数据操作!? 如何保证在高负荷下对数据进行频繁更改时.能保证整体数据的稳定性.和被更改数据的准确性呢!!?? 第2条将给出详细解决方案

(2)解决大数据量数据更新的快速与非溢出性
[1]textdb文件基本常识:
顺序文件.索引文件.关键字文件.等
文件还可按记录的另一特性分成定长记录文件和不定长记录文件! 下面主要分析这些文件的特性.并将各类数据各得其所.充分利用3GL的轻型代码的优势
[2]顺序文件
非定长的顺序文件----这是传统的数据处理方法.也是广大朋友学习中最常用的数据存储容器. 它是有记录按其在文件中的逻辑顺序依次进入存储介质而建立的.

它的特点是:
存取第i个记录,必须先搜索在它之前的i-1个记录.
插入新的记录时只能在文件的末尾.如果需要顺序存储则必须对文件整体进行修改
若要更新文件中的某个记录.则必须将整个文件进行复制
所以.当文件数据越来越大时.添加删除修改.任务便变得非常烦琐.

定长的顺序文件-----用做数据的检索与修改.其中牵涉到两个内容
1)与数据结构B+树原理类似.采用索引集.顺序集.和数据集.顺序集和索引集一起构成一棵B+树的索引部分.分别存储.指向控制行的指针.和索引关键字! 这样在查找或修改时可以采用顺序存取.又可从最高层的索引出发进行按关键字存取.

利用这一思想将举3个例子(都是针对超大型的数据文件):
1,需要进行频繁数据处理的文件.且检索浏览频率大于写频率.建议思想实现采用各行定长顺序索引思想.进行倒排各行
以下程序来自ofstar里的版块索引代码
添加时只要将最新的数据使用 (require/postnew.php)
$newdb="│││$ofstarid││$tid│0│$threadnew│0││";
$newlist=str_pad($newdb,$db_linesize)."\n";
writeover("$dbpath/$fid/list.php",$newlist,"ab");
修改删除时进行倒序查找关键字代码如下(require/dbmodify.php):

function readsearch($filename,$tid,$db_linesize)
{
$size=5000;
$step=0;$end=0;$readsize=$db_linesize+1;$scharray=array();
if($fp=@fopen($filename,"rb+")){
flock($fp,LOCK_EX);
while(!feof($fp)){
$step++;
$offset=-$readsize*$step;
fseek($fp,$offset,SEEK_END);
$line=fread($fp,$readsize);
if(strpos($line,"││$tid│")!==false){
$detail=explode("│",$line);
break;
}elseif($step<$size){
$scharray[]=$line;
}else{
$fastwrite='Y'
}
}
fseek($fp,$offset,SEEK_END);
return array($fp,array_reverse($scharray),$detail,$fastwrite);
}
}

删除时的算法实现:

function write_del($fp,$writearray,$fastwrite)
{
global $db_linesize;
if($fastwrite!="Y"){
$writedb=implode("",$writearray);
fputs($fp,$writedb);
ftruncate($fp,ftell($fp));
}else{
fputs($fp,str_pad(' ',$db_linesize)."\n");
}
}

修改时的算法实现:

function write_alt($fp,$writearray,$fastwrite,$inline)
{
global $db_linesize;
if($fastwrite!="Y"){
array_push($writearray,$inline);
$writedb=implode("",$writearray);
fputs($fp,$writedb);
}else{
fputs($fp,str_pad(' ',$db_linesize)."\n");
fseek($fp,0,SEEK_END);
fputs($fp,$inline);
}
}

检索浏览的算法实现:

$total=$page*$db_perpage;
$linestart=min($total,$statusdetail[7]);
$pernum=$linestart-$total+$db_perpage;
$articleshow=readfrombot($filename,$linestart,$pernum,$db_linesize);
if($page==1){
$threadtop=gettoparray($filename,$db_linesize);
$articleshow=array_merge($threadtop,$articleshow);
}
function readfrombot($filename,$linestart,$linenum,$db_linesize)
{
$offset=max(-($db_linesize+1)*$linestart,-(filesize($filename)-($db_linesize+1)*11));
$num=0;$readb=array();
if($fp=fopen($filename,"rb")){
flock($fp,LOCK_SH);
fseek($fp,$offset,SEEK_END);
while(!feof($fp)&&$num<$linenum){
$readb[]=fgets($fp,100);
$num++;
}
fclose($fp);
}
return array_reverse($readb);
}

以上全部采用倒排数据区域. 对数据的处理只更新需要更改的数据.并非全部写入与读取!
2,针对频繁性添加修改和删除.并每个数据区域含有多个关键字.并对数据进行特定约束的索引表文件
/*在索引中找到最后的所有空行并删除之.将索引中找到一记录不符合条件的以空行填充.并进行在线会员数缓存*/

function substrnbsp($filename)
{
global $db_olsize,$timestamp,$db_onlinetime,$guestinbbs,$userinbbs;
$addnbsp=str_pad(" ",$db_olsize)."\n";
$addfb=str_pad("<?die;?>",$db_olsize)."\n";
$cutsize=$db_olsize+1;$step=$olnum=0;$onlinetime=$timestamp-$db_onlinetime;
$fp=fopen($filename,"rb+");
flock($fp,LOCK_EX);
fputs($fp,$addfb);
fseek($fp,0,SEEK_END);
while(ftell($fp)>$cutsize &&$step<20000){//ftell未测试速度 可以用filesize代替 哨兵$step
$step++;
$offset=-($cutsize*$step);
fseek($fp,$offset,SEEK_END);
$line=fread($fp,28);//读取28个字节.已经包含时间
if(empty($end)){
if(strpos($line,"│")!==false ││ ftell($fp)<=$cutsize){
$end=$offset;//break
}
}
if(strpos($line,"│")!==false){
$detail=explode("│",$line);
if($detail[1]<$onlinetime){
fseek($fp,$offset,SEEK_END);fputs($fp,$addnbsp);
}else{
$olnum++;/*解决在线数目不准确问题*/
}
}
}
if(isset($end)) ftruncate($fp,filesize($filename)+$end+$cutsize);
fclose($fp);
@include 'bbsdata/olcache.php'
if($filename=="bbsdata/guest.php"){$guestinbbs=$olnum;$userinbbs++;}else{$userinbbs=$olnum;$guestinbbs++;}
$olcache="<?php\n\$userinbbs=$userinbbs;\n\$guestinbbs=$guestinbbs;\n?>";
writeover('bbsdata/olcache.php',$olcache);
}

3,针对非频繁性修改.却是频繁性检索与浏览.且记录长度为无规律性
数据结构思想分析:记录将不采用统一的定长.而在控制区中除了存放记录本身以外.再存放每个记录的长度.
比如:
<?die;?>│关键字####,100,│││││这些放数据││││││││││*******************
<?die;?>│关键字####,200,│││││这些放数据││││││││││*******************
含义是第一行为100字节定长.第二行为200定行.以此类推
关键字也采用定长.可以通过关键字索引.
不过这一数据结构对空间的利用率太低.只适合后台管理的大数据量处理程序!!!


并在数据物理存储上采用pack与unpack 对数据的检索会更快.代码如:
/*采用位字符串写入*/

for ($i=0;$i<strlen($code1);$i++)
{
$write=array_pop(unpack("c",substr($code1,$i,1)));
if(strlen($write)==2) $write=?'.$write;
fwrite($fp, $write,3);
}
fclose($fp);

/*采用位字符串读取*/

$fp=fopen("test1.php","rb");
@flock($fp,LOCK_SH);
$code1=fread($fp,filesize("test1.php"));
fclose($fp);
for ($i=0;$i<strlen($code1)/3;$i++)
{
$write.=pack("c",substr($code1,$i*3,3));
}
echo $write;

[3]索引文件
准确的说这是包含文件数据区和索引表两大部分的文件.ofstar 今日到访会员表采用的就是这一典型的索引文件
算法实现采用的是:双向线性链表.每行数据段采用定长! (require/today.php job.php)
对n-->无穷大 对数据的修改与添加只有 3-5项.大大减少了系统的负担!
添加数据如果是双向链表.只需要对3个数据区域进行修改.分别是 头结点区域.头结点数据存放区域.和添加区域
修改数据则需要进行5个数据段分别在添加的基础上加上.修改前一结点的后趋和修改后一结点的前趋
添加算法实现:

$offset=filesize($filename);
if($fp=@fopen($filename,"rb+")){
flock($fp,LOCK_EX);
list($node,$yestime)=nodeinfo($fp,$dbtdsize,$offset);
if($node!=''){/*修改头结点*/
$nowfp=$offset/($dbtdsize+1);
if($node!='NULL') {
fputin($fp,$node,$dbtdsize,$nowfp);
}
if($node!=$nowfp) fputin($fp,$nowfp,$dbtdsize,'node',$node,Y);/*添加数据*/
}
fclose($fp);
}

修改的算法实现是:

if($offset=strpos($todaydata,"\n".$ofstarid.'│')){/*使用精确匹配 必须是"\n".$ofstarid.'│'*/
$offset+=1;
if($fp=@fopen($filename,"rb+")){
flock($fp,LOCK_EX);
list($node,$yestime)=nodeinfo($fp,$dbtdsize,$offset);/*修改头结点*/
$nowfp=$offset/($dbtdsize+1);
if("$nowfp"!=$node && $node!=''){
fputin($fp,$node,$dbtdsize,$nowfp);/*修改头结点指向的数据段*/
list($oldprior,$oldnext)=fputin($fp,$nowfp,$dbtdsize,'node',$node);/*修改需要更新的数据*/
if($oldprior!='node'){
fputin($fp,$oldprior,$dbtdsize,'M',$oldnext);/*修改前一结点的后趋*/
}
if($oldnext!='NULL' && $oldprior!='node'){
fputin($fp,$oldnext,$dbtdsize,$oldprior);/*修改后一结点的前趋*/
}
}
fclose($fp);
}
}

检索的算法实现:

$filename='bbsdata/today.php'
$dbtdsize=100+1;
$seed=$page*$db_perpage;$count=0;
if($fp=@fopen($filename,"rb")){
flock($fp,LOCK_SH);
$node=fread($fp,$dbtdsize);
$nodedb=explode("│",$node);/*头结点在第二个数据段*/
$nodefp=$dbtdsize*$nodedb[1];
fseek($fp,$nodefp,SEEK_SET);
$todayshow=fseeks($fp,$dbtdsize,$seed);/*传回数组*/
fseek($fp,0,SEEK_END);
$count=floor(ftell($fp)/$dbtdsize)-1;
fclose($fp);
}

以下是上面几个算法的主要函数:

function fputin($fp,$offset,$dbtdsize,$prior='M',$next='M',$ifadd='N')
{
$offset=$offset*($dbtdsize+1);/*将行数转换成指针偏移量*/
fseek($fp,$offset,SEEK_SET);
if($ifadd=='N'){
$iddata=fread($fp,$dbtdsize);
$idarray=explode("│",$iddata);
fseek($fp,$offset,SEEK_SET);
}
if($next!='M' && $prior!='M'){/*说明这一数据是被更改的数据段.需要对其他辅助信息进行更改*/
global $ofstarid,$timestamp,$onlineip,$ofstardb;
$idarray[0]=$ofstarid;$idarray[3]=$ofstardb[8];
if($ifadd!='N') $idarray[4]=$timestamp;
$idarray[5]=$timestamp;$idarray[6]=$onlineip;$idarray[7]=$ofstardb[16];$idarray[8]=$ofstardb[17];
}
if($prior=='M') $prior=$idarray[1];
if($next=='M') $next=$idarray[2];
$data="$idarray[0]│$prior│$next│$idarray[3]│$idarray[4]│$idarray[5]│$idarray[6]│$idarray[7]│$idarray[8]│";
$data=str_pad($data,$dbtdsize)."\n";/*定长写入*/
fputs($fp,$data);
return array($idarray[1],$idarray[2]);/*传回数据更新前的上一结点和下一结点*/
}
function nodeinfo($fp,$dbtdsize,$offset)
{
$offset=$offset/($dbtdsize+1);
$node=fread($fp,$dbtdsize);
$nodedb=explode("│",$node);/*头结点在第二个数据段*/
if(is_int($offset)){
$nodedata=str_pad("<?die;?>│$offset│$nodedb[2]│",$dbtdsize)."\n";
fseek($fp,0,SEEK_SET);/*将指针放于文件开头*/
fputs($fp,$nodedata);
return array($nodedb[1],$nodedb[2]);
}else{
return ''
}
}
function fseeks($fp,$dbtdsize,$seed)
{
$num=0;
while($break!=1 && $num<$seed){
$num++;
$sdata=fread($fp,$dbtdsize);
$sdb=explode("│",$sdata);
$sdbnext=$sdb[2]*$dbtdsize;
if($sdbnext!='NULL'){
fseek($fp,$sdbnext,SEEK_SET);
}else{
$break=1;
}
$todayshow[]=$sdata;
}
return $todayshow;
}

[4]关键字文件
php中使用的主要是其思想! 其实上面的两种数据文件都些许使用了这一思想.复杂的就不再累述了! 这里举个简单的也非常实用的例子! 其中主要还借助了定长的思想!
比如对单一主题.的 主题点击率 代码如下( read.php ):

$articlearray=openfile("$dbpath/$fid/$tid.php");
$topic_detail=explode("│",$articlearray[0]);
list($tpc_fb,$tpc_covert,$tpc_author,$rd_icon,$tpc_date,$tpc_title,$tpc_ip,$tpc_sign,$tpc_download,$tpc_rvrc,$tpc_buy,$tpc_ipfrom,$tpc_ifconvert,$tpc_email,$tpc_content,$tpc_null1)=$topic_detail;
list($rd_hit,$rd_islock,$rd_null)=explode(',',$tpc_covert);
$rd_hit=trim($rd_hit);
$rd_hit++;
//$rd_hit=str_pad($rd_hit,8);
$hitwrite="<?die;?>│$rd_hit";
$fp=fopen("$dbpath/$fid/$tid.php","rb+");
flock($fp,LOCK_EX);
fputs($fp,$hitwrite);
fclose($fp);

以上这一套思想完全解决了textdb帖子数据的更新的高效和稳定性问题,对于帖子等大型数据索引进行添加删除.修改都无须全部读取再写入,对在线等修改性频繁的数据.也只对需要修改添加的行(数据)进行写入.

因此无论你处理什么数据都可以应用上面的3种数据结构进行无负载性的添加删除和修改!

(2)保证textdb频繁数据处理时的稳定性
在解决 textdb 负载问题的前提下.必须考虑数据处理的问题.毕竟数据的准确与稳定是一个程序的灵魂.以下我不直接给出具体实现的算法.取而用程序测试比较的方式!
主要讲解两个方面

1) 数据的准确性
大家可能用习惯了传统论坛程序在写入的开始进行EX锁定,下面的两个函数就是现在传统textdb类程序包括论坛所使用的读写函数!

function readover($filename,$method="rb")
{
if($handle=@fopen($filename,$method)){
flock($handle,LOCK_SH);
$filedata=fread($handle,filesize($filename));
fclose($handle);
}
return $filedata;
}
function writeover($filename,$data,$method="wb")
{
$handle=fopen($filename,$method);
flock($handle,LOCK_EX);
fputs($handle,$data);
fclose($handle);
}

这对于小流量的网站而言是更本不会有问题.可是在大流量的网站.这样的函数不得不让人质疑textdb的稳定性和数据的准确性!
因为同时请求更新同一数据有好几个时.数据的不准确性便产生了.比如 当你发贴时在索引表中进行写入或修改你的索引信息.需要对索引进行琐定.可是如果你在读完索引后正准备写入时.另一个线程也在共享的前提下读取数据完毕.也正准备写入.这时如果是你的线程先进入了锁定写入.那么等你写完后.他将马上写入不包含你索引信息的内容.这便造成了所谓的帖子丢失的假象! 当然如果你使用了(一)中的负载的定长索引的某种数据结构.这一现象发生的几率将几乎为0.因为它对索引操作不再是全部写!
下面给出读写时保证数据的准确性算法:
function readlock($filename,$method="rb+")
{
$file=fopen($filename,$method);
flock($file,LOCK_EX);
$filedata=fread($file,filesize($filename));
rewind($file);
return array($file,$filedata);
}
function writelock($filename,$data,$handle)
{
fputs($handle,$data);
ftruncate($handle,strlen($data));
fclose($handle);
}

这样的函数实现便完美解决了任何场合保证数据的准确性!!!!(上面两个函数已解决数据的稳定性) 大家可以编写程序测试以上的科学性!

2) 数据的稳定性
下面先给出测试的一个程序:

function readlock($filename,$method="wb")
{
$file=fopen($filename,$method);
flock($file,LOCK_EX);
$filedata=fread($file,filesize($filename));
return array($file,$filedata);
}
function writelock($filename,$data,$handle)
{
fputs($handle,$data.$data);
fclose($handle);
}
function filelock($filename,$method="wb")
{
$filedb=openfile($filename);
$handle=fopen($filename,$method);
flock($handle,LOCK_EX);
return array($handle,$filedb);
}
$filename='c.php'
list($file,$ofstarfile)=readlock($filename);
$ofstarfile=explode('│',$ofstarfile);
$ofstarfile[4]++;$ofstarfile[5]++;
echo $ofstarfile[4];echo'<br>'
$ofstardb=implode("│",$ofstarfile);
echo $ofstardb;
for($I=0;$I<1500000;$I++)//增加多个线程同时请求的时间
{
$A=$B=2;
}
writelock($filename,$ofstardb,$file);

***********************************
c.php的数据内容是
<?die;?>│42 │1│1│101│101│0│64│1067443200│1067961600│fengyu│fengyu│fengyu││1│2003-10-22 13:33│天天天│

大家可以放在 unix 与NT上进行测试.
具体测试方法是 同时运行这个程序达到多线程同时请求同一数据 如果数据段不发生紊乱且第4.5数据段的值不断增加说明是稳定的.如果发生紊乱则不是稳定的.注意需要线程同时请求大于4个以上!
具体测试结果是:在NT空间上大于4个线程同时请求的出现紊乱的几率为 50--100%具体依赖于操作系统的多线程服务器.
linux/freebsd上 进行大于4个线程同时请求出现的几率为0-0.001%也就是说几乎为 0
当然出现错误的几率还是有的! 也证实过! 具体要求是几十个线程同时请求.具体的问题在于php中的系统函数在NT的多线程操作系统与服务器下的不兼容问题.
针对传统textdb的数据不准确和不稳定问题--------彻底解决方案是:
使用以下的写函数:

/*写入数据保证稳定性*/
在给出写入的稳定性函数前.先说明一个问题.
大家可能为了让速度更为快速,常用直接包含 .php 文件直接得到值. 当然这一方法很有效.不过在对于数据处理频繁的文件.切记不可使用 include $filename; 然后对数据处理后 writeover(); 因此建议对频繁处理数据的文件采用共享读取!
下面为解决稳定性的实现方法:

function writeover($filename,$data,$method="rb+")
{
touch($filename);/*文件不存在则创建之.可以采用file_exists验证并其他创建文件函数代替.测试结果效率相当*/
$handle=fopen($filename,$method);
flock($handle,LOCK_EX);
fputs($handle,$data);
if($method=="rb+") ftruncate($handle,strlen($data));
fclose($handle);
}
function readlock($filename,$method="rb+")
{
$file=fopen($filename,$method);
flock($file,LOCK_EX);
$filedata=fread($file,filesize($filename));
rewind($file);
return array($file,$filedata);
}
function writelock($filename,$data,$handle)
{
fputs($handle,$data);
ftruncate($handle,strlen($data));
fclose($handle);
}

这便圆满解决了 textdb 数据处理的稳定性问题
加上解决数据的准确性问题. 有理由相信 textdb 不再是脆弱的数据处理”容器”!

( 以上负载算法和稳定性算法归属Ofstar board .请务必尊重我们的劳动成果! )

(三)textdb整体效率提高的细节性问题
其实这个主要是看程序的水平了.不过站得更高收获总是可以更丰厚.下面将一下ofstar内部研究的 php—textdb数据处理的一写算法或是一些技巧:
1)获取ip地址来源

function cvipfrom($onlineip)
{
$detail=explode(".",$onlineip);
if (file_exists("ipdata/$detail[0].txt"))
$filename="ipdata/$detail[0].txt";
else
$filename="ipdata/0.txt";
for ($i=0; $i<=3; $i++)
{
$detail[$i] = sprintf("%03d", $detail[$i]);
}
$onlineip=join(".",$detail);
$db=fopen($filename,"rb");
flock($db,LOCK_SH);
$onlineipdb=fread($db,filesize($filename));
if($ofstarset=strpos($onlineipdb,"$detail[0].$detail[1].$detail[2]")){
$ipfrom=ipselect($db,$ofstarset,$onlineip);
}elseif($ofstarset=strpos($onlineipdb,"$detail[0].$detail[1]")){
$ipfrom=ipselect($db,$ofstarset,$onlineip);
}elseif($ofstarset=strpos($onlineipdb,$detail[0])){
$ipfrom=ipselect($db,$ofstarset,$onlineip);
}
fclose($db);
if(empty($ipfrom)) $ipfrom='未知地址'
return $ipfrom;
}
function ipselect($db,$offset,$onlineip){
fseek($db,$offset,SEEK_SET);
$getcontent=fgets($db,100);
$iparray=explode("│",$getcontent);
if ($onlineip>=$iparray[0] && $onlineip<=$iparray[1]) return $iparray[2].$iparray[3];
}

这个算法将比比传统效率高3-5倍.具体思想是.在处理非规则性行时.大可不必行行进行 explode 要知道这样将耗用很大的时间.其实可以变通过来先全部读取.使用strpos 得到关键字的位置! 再使用指针偏移! 条件是关键字需要在行的开头! 这样处理起来比较方便.当然如果不在开头也可以.只要使用两次 strops 就可以找到具体位置,具体可参看ofstar 在线会员的代码

2)return 与 global
在函数中,传递数组时
使用 return 比使用 global 要高效
比如
function userloginfo($usertemp){
$detail=explode("│",$usertemp);
return $detail;
}
$login=userloginfo($userdb);

function userloginfo($usertemp){
global $detail;
$detail=explode("│",$usertemp);
}
userloginfo($userdb);
要高效
3)
判断的时候尽量使用if($a==他的值) 否定的时候尽量使用if(empty($a)),因为这样程序运行更快速

4)对小数据操作避免使用 file()和 fget(效率低)
算法如下:

function openfile($filename,$style='Y')
{
if($style=='Y'){
$filedata=readover($filename);
$filedata=str_replace("\n","\n<:ofstar:>",$filedata);
$filedb=explode("<:ofstar:>",$filedata);
//array_pop($filedb);
$count=count($filedb);
if($filedb[$count-1]==''││$filedb[$count-1]=="\r"){unset($filedb[$count-1]);}
if(empty($filedb)){$filedb[0]="";}
return $filedb;
}else{
$filedb=file($filename);
return $filedb;
}
}

/*openfile函数无论在速度还是稳定上都大于file系统函数,不过openfile是具有负载问题的.所以有时 file 函数在解决大型数据非常有用*/

5)同一页面刷新并不更新在线数据.代码如下
if($timestamp-$lastvisit>$db_onlinetime││ ($fid&& $fid!=$HTTP_COOKIE_VARS['lastfid'])││($HTTP_COOKIE_VARS['lastfid']!='' && $star_action=='hm'))
{
$runfc='Y'
include "./require/userglobal.php";
}

6)帖子浏览时判断作者是否在线时.采用的是 cookie 加 strops 进行快速查找,大大提高了程序运行的效率
if(!$HTTP_COOKIE_VARS['forum_online'])
{
$onlinearray=openfile('bbsdata/online.php');
$count_ol=count($onlinearray);
for ($i=1; $i<$count_ol; $i++)
{
$rd_onlinedb=explode("│",$onlinearray[$i]);
if($rd_onlinedb[0]!='隐身会员')
{
if ($timestamp-$rd_onlinedb[1]<=$db_onlinetime )
$forum_online.='│'.$rd_onlinedb[0];
}
}
setCookie('forum_online',$forum_online, $cookietime,$ckpath,$ckdomain,$secure);
}
@strpos($forum_online,$tpc_author) !== false ? $read[ifonline]="<img src='$imgpath/$stylepath/read/online.gif' alt='该用户目前在线'>":$read[ifonline]="<img src='$imgpath/$stylepath/read/offonline.gif' alt='该用户目前不在线'>";


(四)对数据的检索
经过多次测试采用 索引中读取数据id.使用 fopen 文件. Fread 得到帖子数据.不再采用fgets 读取数据. 大大提高了检索的速度.由于在程序效率上已经推证过 使用 file()函数的速度问题.所以 ofstar 的检索里不采用 file()读取数据,实践证明使用这一方法 textdb检索对 cpu 和内存耗用极低!

(五)textdb安全维护
无论是.RDBMS还是textdb 程序安全都牵涉到3个方面!这里就解说三方面的textdb解决安全问题的方法: 程序数据接口安全问题.程序恶意代码攻击,服务器的安全问题

1) 程序数据接口安全问题
由于数据是以文件直接保存在空间上的.所以必须对数据文件采用加密或是特定的防护.常见的方法有.使用特定的目录名.采用随机的目录名为数据存放的目录! 这一方法安全性可以保证.但是万一目录名被获知.将是致命的打击.因此 ofstar 对数据文件采用 .php 可执行文件结尾.对文件内第一行 加上 <?die?> 将外来的访问屏蔽!! 彻底解决textdb 数据文件的安全问题.!

2) 程序恶意代码攻击
直接讲 ofstar的思想:在保证防止普通变量攻击的同时,程序方面全部防止自动提交所带来的安全隐患,并全智能判断附件可能存在的恶意代码!自动过滤与屏蔽恶意会员所带来的恶意代码等

3) 服务器的安全问题
这里只针对linux/unix 多用户的操作系统.利用程序创建帖子数据和用户数据目录,从而避免了要手动设置‘777’属性而造成数据文件属主的问题.这样既方便安装又解决了unix/ linux系统textdb数据的安全问题。

相信. Ofstar的一次次进步都会增强您的信心.更是您明智的选择!
新版本的开发中.我们会在论坛的负载、稳定性和速度的强大优势上.继续加强程序的安全性.并在功能和易用性上大上台阶....


<!---->
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值