`
jackchen0227
  • 浏览: 146802 次
  • 性别: Icon_minigender_1
  • 来自: 帝都
社区版块
存档分类
最新评论

【zz】Discuz X缓存机制浅析

    博客分类:
  • php
阅读更多

  第二版

首发于:http://www.PHPig.net,转载请注明。

Discuz X中,缓存核心函数在function_core.php和function_cache.php中。其中以updatecache和loadcache两个函数最为核心。弄清楚了这两个函数之后,完全能剥离出来自己用,或者仿它的写法自己创建缓存了。

这里简单叙述一下X里面,缓存的机制。
X的缓存,主要是存储不经常变动的数据,存储方式可以选择数据库,或者文件。下面举例说明。我们可以在后台的admincp_click.php,看到 updatecache('click'),证明click是使用了缓存机制的。Click就是表态图标,头像什么的信息,路过,雷人,鸡蛋等等,这些信息是​基本不修改的,并且会在前台很多地方用到。而如果不使用缓存的话,则每次都需要遍历一次click表,而如果有100个表态图像的话则会读100次库,每篇日志都会有cl​ick信息,如果有100篇日志则会读click表10000次。

X的做法就是,把类似click表的内容,序列化,存放在common_syscache表中,这样每次只需要读一次库,或者存放在文件中,每次都读这个文件。下面我们详​细看看代码是怎么运行的。我们这里模拟一个需要缓存的表message,只有两个字段,subject和content。当然 message这样的经常更新的数据是不适合缓存的,这里只是举例方便。
function updatecache($cachename = '') {

    global $_G;

    static $cachelist = array(''message); //把需要缓存的数据名,可自己添加。

    $updatelist = empty($cachename) ? $cachelist : (is_array($cachename) ? $cachename : array($cachename));
    foreach($updatelist as $value) {
        getcachearray($value); //填充缓存数据
    } 

 这里看看getcachearray()代码

function getcachearray($cachename, $script = '') {
    global $_G;

    $cols = '*';
    $conditions = '';
    $timestamp = TIMESTAMP;
    switch($cachename) { //根据缓存名称按要求写相关代码,什么需要缓存,什么不需要缓存,我这里的conditions用默认的,就是缓存全部数据。
        case 'message':
    $table = 'message';
            break;
    …………
    }
    $data = array();
        $query = DB::query("SELECT $cols FROM ".DB::table($table)." $conditions");
    //读库,存为数组。
        switch($cachename) {
            case 'message':
                while($row = DB::fetch($query)) {
                    $data['subject'][$row['id']] = $row['subject'];
                    $data['content'][$row['id']] = $row['content'];
                    $data['dateline'][$row['id']] = $row['dateline'];
                }
    
        save_syscache($cachename, $data); //序列化存到syscache表中。
        return true; 
}

 

看看save_syscache()是干嘛的。

function save_syscache($cachename, $data) {
    static $isfilecache, $allowmem;
    if($isfilecache === null) {
        $isfilecache = getglobal('config/cache/type'); //取缓存类型,是file,还是sql。
        $allowmem = memory('check'); //判断是否使用Memcached
    }

    if(is_array($data)) {
        $ctype = 1;
        $data = addslashes(serialize($data)); //序列化
    } else {
        $ctype = 0;
    }
    //入库
    DB::query("REPLACE INTO ".DB::table('common_syscache')." (cname, ctype, dateline, data) VALUES ('$cachename', '$ctype', '".TIMESTAMP."', '$data')");

    //memcached启用的话,清空缓存
    $allowmem && memory('rm', $cachename); 
    //缓存file存在的话,删除文件
    $isfilecache && @unlink(DISCUZ_ROOT.'./data/cache/cache_'.$cachename.'.php');
} 

 

总结一下updatecache()的作用,读原始库,这里是message表,序列化存到syscache表的一条记录,并且清空memcached缓存和缓存的fil​e。
Updatecache => getcachearray => save_syscache

下面我们研究缓存模块的下半部分,loadcache();

function loadcache($cachenames, $force = false) {
    global $_G;
    static $loadedcache = array();
    $cachenames = is_array($cachenames) ? $cachenames : array($cachenames);
    $caches = array();
    foreach ($cachenames as $k) {
        if(!isset($loadedcache[$k]) || $force) {
            $caches[] = $k;
            $loadedcache[$k] = true;
        }
    }

if(!empty($caches)) {
        $cachedata = cachedata($caches); //读数据库缓存或者file缓存
        foreach($cachedata as $cname => $data) {
            $_G['cache'][$cname] = $data;
            $cachearr = $_G['cache'][$cname];
        }
    }
    return $cachearr; 

 

function cachedata($cachenames) {
    static $isfilecache, $allowmem;

    if($isfilecache === null) {
        $isfilecache = getglobal('config/cache/type') == 'file';
        $allowmem = memory('check');
    }

    $data = array();
    $cachenames = is_array($cachenames) ? $cachenames : array($cachenames);
    if($allowmem) {
        $newarray = array();
        foreach ($cachenames as $name) {
            $data[$name] = memory('get', $name);//通过memcached取值
            if($data[$name] === null) {
                $data[$name] = null;
                $newarray[] = $name;
            }
        }
        if(empty($newarray)) {
            return $data;
        } else {
            $cachenames = $newarray;
        }
    }

    if($isfilecache) {
        $lostcaches = array();
        foreach($cachenames as $cachename) {
    //这里include缓存file
            if(!@include_once(DISCUZ_ROOT.'./data/cache/cache_'.$cachename.'.php')) {
                $lostcaches[] = $cachename;
            }
        }
//如果已经有file,则不走$lostcaches[] = $cachename,$lostcaches没值,直接return file中的$data。
        if(!$lostcaches) {
            return $data;
        }
        $cachenames = $lostcaches;
        unset($lostcaches);
    }
    $query = DB::query("SELECT /*!40001 SQL_CACHE */ * FROM ".DB::table('common_syscache')." WHERE cname IN ('".implode("','", $cachenames)."')");
    while($syscache = DB::fetch($query)) {
        $data[$syscache['cname']] = $syscache['ctype'] ? unserialize($syscache['data']) : $syscache['data'];
//通过memcached存到内存里
        $allowmem && (memory('set', $syscache['cname'], $data[$syscache['cname']]));
//创建file,数据存到file中
        if($isfilecache) {
            $cachedata = '$data[\''.$syscache['cname'].'\'] = '.var_export($data[$syscache['cname']], true).";\n\n";
            if($fp = @fopen(DISCUZ_ROOT.'./data/cache/cache_'.$syscache['cname'].'.php', 'wb')) {
                fwrite($fp, "<?php\n//Discuz! cache file, DO NOT modify me!\n//Identify: ".md5($syscache['cname'].$cachedata)."\n\n$cachedata?>");
                fclose($fp);
            }
        }
    }

    foreach ($cachenames as $name) {
        if($data[$name] === null) {
            $data[$name] = null;
            $allowmem && (memory('set', $name, array()));
        }
    }

    return $data;
} 

  

分享到:
评论

相关推荐

    base zz zz zz zz

    base zz zz zz zz zz base zz zz zz zz zz base zz zz zz zz zz base zz zz zz zz zz

    ZZ561401.CAB

    ZZ561401.CAB ZZ561401.CAB ZZ561401.CAB

    wincc AX NF ZZ

    wincc SIMATIC WinCC是第一个使用最新的32位技术的过程监视系统,具有良好的开放性和灵活性。 从面市伊始,用户就对SIMATIC WinCC印象深刻。

    zz CAD快速计算长度插件

    在CAD中想要快速测量长度,在CAD工具栏找到加载应用程序,再点击加载 加载成功后在输入栏输入“zz”(不分大小写)在选择你需要测量的线段即可。

    超出NLO QCD的高横向动量的ZZ产生

    我们研究了四轻子最终状态ℓ+ℓ-ℓ+ℓ-的产生,这些状态主要由一对弱电Z玻色子ZZ产生。 使用LoopSim方法,我们合并ZZ和ZZ + jet的NLO QCD结果,并获得ZZ产生的近似NNLO预测。 还包括对ZZ过程的精确胶子融合环平方的...

    Zz归零.LSP

    cad标高归零,好用的

    tokyo-ghoul-2017_indonesian-1688080_TOKYO_zz_

    标题中的“tokyo-ghoul-2017_indonesian-1688080_TOKYO_zz_”暗示了这是一个关于2017年动画片《东京食尸鬼》(Tokyo Ghoul)的资源,可能是影片的印尼语版本。"indonesian"表明是印尼语言的配音或字幕,而"1688080...

    zz809.com留言本

    它不仅可以让开发者了解留言本系统的内部运行机制,还能为他们提供一个实战性的学习案例,以便于理解和应用到自己的项目中。留言板类的应用广泛存在于各种网站和论坛中,它是构建社交互动和用户反馈的重要工具。 在...

    中医大夫助理信息系统 zz-doctor

    《中医大夫助理信息系统 zz-doctor 深度解析》 中医大夫助理信息系统“zz-doctor”是一款基于Android平台的应用程序,旨在为中医医生提供智能化、便捷化的诊疗辅助工具。通过深入剖析这款应用的源码,我们可以了解...

    3_Level_ZZ_Semafor.zip_3 level_zz_3_Level_ZZ_semafor_ZZ Semafor_

    ,主图指标,顶底信号,突破,转折信号,都很明显

    ZZ_MODIFIED_GEEBINF.ENS.zip endnote的样式文件

    标题中的“ZZ_MODIFIED_GEEBINF.ENS.zip”是一个压缩包文件,主要包含一个名为“ZZ_MODIFIED_GEEBINF.ENS”的文件。这个文件是一种特殊格式,用于定义EndNote的引用样式。EndNote是一款强大的文献管理软件,广泛应用...

    ZZ Fibo Trader - MetaTrader 5EA.zip

    《ZZ Fibo Trader - MetaTrader 5 EA 深度解析》 ZZ Fibo Trader 是一款专为 MetaTrader 5(MT5)平台设计的自动交易专家顾问(EA),其核心在于结合了斐波那契回调线分析和抛物线止损系统,为交易者提供了智能化的...

    TZ200XSQ-ZZ3D_id2434_x_t.prt

    TZ200XSQ-ZZ3D_id2434_x_t.prt

    emqx-centos7-v3.1

    EMQ X (Erlang/Enterprise/Elastic MQTT Broker) 是基于 Erlang/OTP 平台开发的开源物联网 MQTT 消息服务器。Erlang/OTP 是出色的软实时(Soft-Realtime)、低延时(Low-Latency)、分布式(Distributed) 的语言平台。...

    变形版SD ZZ高达 纸模型

    "变形版SD ZZ高达"是一款深受高达爱好者喜爱的纸模型,它源于日本著名的机器人动漫《机动战士Z高达》中的角色。SD(Super Deformed)是日本动漫中的一个术语,意为超级变形,通常指的是角色被夸张地简化和可爱化,...

    zz_layer.rar

    zz_layer.il是源代码,install.bat是安装的 使用举例:zz 1-3 4 126 127 层号定义,与PADS类似:1~120是etch ;SolderMask: 121(top) 128(bot) ;Silkscreen: 126(top) 129(bot) ;Assembly: 127(top) 130(bot) ;Paste...

    我的资源zzzzzzzzzzzzz

    我的资源zzzzzzzzzzzzz

    TIA V16 AX NF ZZ.rar

    博途V16授权 博途V16授权 博途V16授权 博途V16授权 TIA V16 AX NF ZZ TIA V16 AX NF ZZ TIA V16 AX NF ZZ TIA V16 AX NF ZZ TIA V16 AX NF ZZ

Global site tag (gtag.js) - Google Analytics