本篇分析下SugarCRM的缓存,缓存文件主要存放在./include/SugarCache里,实例化主要是SugarCache::instance()方法来实现。

// ./include/SugarCache/SugarCache.php
class SugarCache
{const EXTERNAL_CACHE_NULL_VALUE = "SUGAR_CACHE_NULL_ZZ";protected static $_cacheInstance;/*** @var true if the cache has been reset during this request, so we no longer return values from*      cache until the next reset*/public static $isCacheReset = false;private function __construct() {}/*** initializes the cache in question* 初始化缓存*/protected static function _init(){$lastPriority = 1000;// 返回的是include/SugarCache路径及定制的custome/include/SugarCache中详细路径数组$locations = SugarAutoLoader::getFilesCustom('include/SugarCache');// 如果为空的话,则取SugarCRM默认的缓存类if(empty($locations)) {$locations = array('include/SugarCache/SugarCacheMemory.php');}// 依次加载include/SugarCache文件,本身文件除外// 并实例化SugarCacheAbstract的子类,也就是继承SugarCacheAbstract的类// 这里最终返回的实例条件为:$lastPriority为最小并且$cacheInstance->useBackend()成立/*SugarCacheAbstract          1000SugarCacheMemory            999   为SugarCRM自带的缓存,当所有的缓存都没打开时返回此实例SugarCacheFile              990SugarCachesMash             950SugarCacheAPC               940SugarCacheWincache          930SugarCacheRedis             920SugarCacheZend              910SugarCacheMemcached         900SugarCacheMemcache          900*/foreach ( $locations as $location ) {$cacheClass = basename($location, ".php");if($cacheClass == 'SugarCache') continue;require_once $location;if ( class_exists($cacheClass) && is_subclass_of($cacheClass,'SugarCacheAbstract') ) {$GLOBALS['log']->debug("Found cache backend $cacheClass");$cacheInstance = new $cacheClass();if ( $cacheInstance->useBackend()&& $cacheInstance->getPriority() < $lastPriority ) {$GLOBALS['log']->debug("Using cache backend $cacheClass, since ".$cacheInstance->getPriority()." is less than ".$lastPriority);self::$_cacheInstance = $cacheInstance;$lastPriority = $cacheInstance->getPriority();}}}}/*** Returns the instance of the SugarCacheAbstract object, cooresponding to the external* cache being used.* 实例化缓存类* 条件:必须为SugarCacheAbstract类的子类,不是的话,就初始化*/public static function instance(){if ( !is_subclass_of(self::$_cacheInstance,'SugarCacheAbstract') )self::_init();return self::$_cacheInstance;}/*** Try to reset any opcode caches we know about** @todo make it so developers can extend this somehow*/public static function cleanOpcodes(){// APCif ( function_exists('apc_clear_cache') && ini_get('apc.stat') == 0 ) {apc_clear_cache();}// Wincacheif ( function_exists('wincache_refresh_if_changed') ) {wincache_refresh_if_changed();}// Zendif ( function_exists('accelerator_reset') ) {accelerator_reset();}// eAcceleratorif ( function_exists('eaccelerator_clear') ) {eaccelerator_clear();}// XCacheif ( function_exists('xcache_clear_cache') && !ini_get('xcache.admin.enable_auth') ) {$max = xcache_count(XC_TYPE_PHP);for ($i = 0; $i < $max; $i++) {if (!xcache_clear_cache(XC_TYPE_PHP, $i)) {break;}}}}/*** Try to reset file from caches*/public static function cleanFile( $file ){// APCif ( function_exists('apc_delete_file') && ini_get('apc.stat') == 0 ){apc_delete_file( $file );}}
}// SugarAutoLoader::getFilesCustom('include/SugarCache');
public static function getFilesCustom($dir, $get_dirs = false, $extension = null) {return array_merge(self::getDirFiles($dir, $get_dirs, $extension), self::getDirFiles("custom/$dir", $get_dirs, $extension));
}public static function getDirFiles($dir, $get_dirs = false, $extension = null, $recursive = false) {// In development mode we don't have the filemap available. To avoid// full rebuilds on every page load, only load what we need at this// point.// 开发者模式中,不会有./cache/file_map.php和class_map.php文件,也没有$filemap映射类,每次都需重新生成if (self::$devMode) {$data = self::scanSubDir($dir);} else {// 如果映射类也为空,那么则要重新走初始化了if (empty(self::$filemap)) {self::init();}$data = self::$filemap;}// remove leading . if present$extension = ltrim($extension, ".");$dir = rtrim($dir, "/");$parts = explode('/', $dir);foreach ($parts as $part) {if (empty($part)) {continue; // allow sequences of /s}if (!isset($data[$part])) {return array();}$data = $data[$part];}// 此步时,$data为数组嘴里层的文件列表// 接下的flatten返回的是加上路劲的文件列表/*Array([SugarCache.php] => 1[SugarCacheAbstract.php] => 1[SugarCacheAPC.php] => 1[SugarCacheFile.php] => 1[SugarCacheMemcache.php] => 1[SugarCacheMemcached.php] => 1[SugarCacheMemory.php] => 1[SugarCacheRedis.php] => 1[SugarCachesMash.php] => 1[SugarCacheWincache.php] => 1[SugarCacheZend.php] => 1)*/if (!is_array($data)) {return array();}return self::flatten($dir, $data, $get_dirs, $extension, $recursive);
}protected function flatten($dir, array $data, $get_dirs, $extension, $recursive) { //lizhi$result = array();foreach ($data as $file => $nodes) {// check extension if givenif (!empty($extension) && pathinfo($file, PATHINFO_EXTENSION) != $extension) {continue;}$path = $dir . '/' . $file;// get dirs or files depending on $get_dirsif (is_array($nodes) == $get_dirs) {$result[] = $path;}if ($recursive && is_array($nodes)) {$result = array_merge($result, self::flatten($path, $nodes, $get_dirs, $extension, $recursive));}}// 返回/*Array([0] => include/SugarCache/SugarCache.php[1] => include/SugarCache/SugarCacheAbstract.php[2] => include/SugarCache/SugarCacheAPC.php[3] => include/SugarCache/SugarCacheFile.php[4] => include/SugarCache/SugarCacheMemcache.php[5] => include/SugarCache/SugarCacheMemcached.php[6] => include/SugarCache/SugarCacheMemory.php[7] => include/SugarCache/SugarCacheRedis.php[8] => include/SugarCache/SugarCachesMash.php[9] => include/SugarCache/SugarCacheWincache.php[10] => include/SugarCache/SugarCacheZend.php)*/return $result;
}

缓存实例加载流程分析完后,接下来就看看调用分析了,这里假设只用系统里的默认缓存类SugarCacheMemory

./include/SugarCache/SugarCache.php
sugar_cache_retrieve($cache_key);function sugar_cache_retrieve($key)
{// 这里会调用SugarCacheMemory的父类SugarCacheAbstract中的__get魔术方法// 缓存类中的ttl并没有实现,只是实现了简单的存入、获取及销毁return SugarCache::instance()->$key;
}./include/SugarCache/SugarCacheMemory.php
class SugarCacheMemory extends SugarCacheAbstract
{/*** @see SugarCacheAbstract::$_priority*/protected $_priority = 999;/*** @see SugarCacheAbstract::useBackend()*/public function useBackend(){// we'll always have this backend availablereturn true;}/*** @see SugarCacheAbstract::_setExternal()** Does nothing; cache is gone after request is done.*/protected function _setExternal($key,$value){}/*** @see SugarCacheAbstract::_getExternal()** Does nothing; cache is gone after request is done.*/protected function _getExternal($key){}/*** @see SugarCacheAbstract::_clearExternal()** Does nothing; cache is gone after request is done.*/protected function _clearExternal($key){}/*** @see SugarCacheAbstract::_resetExternal()** Does nothing; cache is gone after request is done.*/protected function _resetExternal(){}
}./include/SugarCache/SugarCacheAbstract.php
abstract class SugarCacheAbstract
{public function __get($key){if ( SugarCache::$isCacheReset )return null;$this->_cacheRequests++;if ( !$this->useLocalStore || !isset($this->_localStore[$key]) ) {$this->_localStore[$key] = $this->_getExternal($this->_keyPrefix.$key);if ( isset($this->_localStore[$key]) ) {$this->_cacheExternalHits++;}else {$this->_cacheMisses++;}}elseif ( isset($this->_localStore[$key]) ) {$this->_cacheLocalHits++;}if ( isset($this->_localStore[$key]) ) {return $this->_localStore[$key];}return null;}public function __set( $key, $value){$this->set($key, $value);}public function set($key, $value, $ttl = null){if ( is_null($value) ){$value = SugarCache::EXTERNAL_CACHE_NULL_VALUE;}if ( $this->useLocalStore ){$this->_localStore[$key] = $value;}if( $ttl === NULL ){$this->_setExternal($this->_keyPrefix.$key,$value);}else if( $ttl > 0 ){//For BC reasons the setExternal signature will remain the same.$previousExpireTimeout = $this->_expireTimeout;$this->_expireTimeout = $ttl;$this->_setExternal($this->_keyPrefix.$key,$value);$this->_expireTimeout = $previousExpireTimeout;}}
}

这里说说注意点,如果项目环境中装了redis【Memcached、Memcache也适合,如果同时装几种符合的缓存,那么可以看看上面缓存类的优先权】,那么得小心了,因为在实例化缓存时,会实例化redis,因为redis的缓存类小于项目本身的。如果项目中调用了sugar_cache_reset_full方法会清空redis所连接的数据库,切记切记。若是项目和redis部署在一起,有两种方法可以避过,一是注释掉清空redis库的方法【在./include/SugarCache/SugarCacheRedis.php中注释掉_resetExternal方法中的$this->_getRedisObject()->flushAll();语句】,一是在配置文件中把external_cache_disabled_redis置为true。

最后看看SugarCache类中调用缓存的最终方法

/*** Retrieve a key from cache.  For the Zend Platform, a maximum age of 5 minutes is assumed.** @param String $key -- The item to retrieve.* @return The item unserialized*/
function sugar_cache_retrieve($key)
{return SugarCache::instance()->$key;
}/*** Put a value in the cache under a key** @param String $key -- Global namespace cache.  Key for the data.* @param Serializable $value -- The value to store in the cache.*/
function sugar_cache_put($key, $value, $ttl = null)
{SugarCache::instance()->set($key,$value, $ttl);
}/*** Clear a key from the cache.  This is used to invalidate a single key.** @param String $key -- Key from global namespace*/
function sugar_cache_clear($key)
{unset(SugarCache::instance()->$key);
}/*** Turn off external caching for the rest of this round trip and for all round* trips for the next cache timeout.  This function should be called when global arrays* are affected (studio, module loader, upgrade wizard, ... ) and it is not ok to* wait for the cache to expire in order to see the change.*/
function sugar_cache_reset()
{SugarCache::instance()->reset();SugarCache::cleanOpcodes();
}/*** Flush the cache in its entirety including the local and external store along with the opcodes.*/
function sugar_cache_reset_full()
{SugarCache::instance()->resetFull();SugarCache::cleanOpcodes();
}/*** Clean out whatever opcode cache we may have out there.*/
function sugar_clean_opcodes()
{SugarCache::cleanOpcodes();
}/*** Internal -- Determine if there is an external cache available for use.** @deprecated*/
function check_cache()
{SugarCache::instance();
}/*** This function is called once an external cache has been identified to ensure that it is correctly* working.** @deprecated** @return true for success, false for failure.*/
function sugar_cache_validate()
{$instance = SugarCache::instance();return is_object($instance);
}/*** Internal -- This function actually retrieves information from the caches.* It is a helper function that provides that actual cache API abstraction.** @param unknown_type $key* @return unknown* @deprecated* @see sugar_cache_retrieve*/
function external_cache_retrieve_helper($key)
{return SugarCache::instance()->$key;
}

SugarCRM源码分析之缓存相关推荐

  1. Android UIL图片加载缓存源码分析-内存缓存

    本篇文章我们来分析一下著名图片加载库Android-Universal-Image-Loader的图片缓存源码. 源码环境 版本:V1.9.5 GitHub链接地址:https://github.co ...

  2. java disruptor压测_Java并发框架Disruptor实现原理与源码分析(二) 缓存行填充与CAS操作...

    ##缓存行填充 关于缓存行填充在我个人的印象里面第一次看到是在Java的java.util.concurrent包中,因为当时很好奇其用法背后的逻辑,所以查了很多资料才明白到底是怎么回事*(也许事实上 ...

  3. SugarCRM源码分析之数据库连接

    这里详细介绍下SugarCRM里的数据库连接相关逻辑,数据库的相关配置在config.php中的dbconfig和dbconfigoption数据项. 'dbconfig' => array ( ...

  4. SugarCRM源码分析之日志

    本章主要介绍下SugarCRM里的日志处理类. // 获取日志实例,以后调用日志处理时,只需类似$GLOBAL['log']->fatal('msg');即可 $GLOBALS['log'] = ...

  5. SugarCRM源码分析之ControllerFactory

    本篇主要分析控制器工厂,这个很重要,因为在页面上操作时,其实都是操作相关模块的相关方法,而相关模块对应到SuarCRM中都是通过控制器工厂来加载各个不同的控制器的. class SugarApplic ...

  6. ecshop源码分析——静态缓存static_c…

    http://guozhiwei.javaeye.com/blog/673291 http://www.phpall.cn static_caches缓存文件 存放在ecshop/temp/stati ...

  7. ceph bluestore 源码分析:刷缓存(trim)逻辑

    环境 ceph版本:12.2.1 部署模式:ec 2+1 osd: 3个 且资源池已经有数据 执行命令:ceph daemon osd.0 flush_store_cache 进行刷缓存.即将dump ...

  8. MyBatis学习笔记-源码分析篇

    引言 SQL 语句的执行涉及多个组件,其中比较重要的是 Executor. StatementHandler. ParameterHandler 和 ResultSetHandler. Executo ...

  9. 实际测试例子+源码分析的方式解剖MyBatis缓存的概念

    前言: 前方高能! 本文内容有点多,通过实际测试例子+源码分析的方式解剖MyBatis缓存的概念,对这方面有兴趣的小伙伴请继续看下去~ 欢迎工作一到五年的Java工程师朋友们加入Java架构开发:79 ...

最新文章

  1. BagNet超越 AlexNet,在ImageNet 上实现最先进结果!
  2. 华为手机所有图标变黑_华为官博科普手机状态栏小图标含义,总共分为4大类...
  3. 南通大学计算机专业分数线2020,2020南通大学录取分数线_历年各专业分数线(2017-2019)_各省投档线_一品高考网...
  4. java用数组实现随机不重复抽奖
  5. 用python画数学函数图像教程_Python 绘制你想要的数学函数图形
  6. “丑东西”,正在成为一门生意
  7. 【java笔记】Iterator迭代器 增强for
  8. 数学基础加强3---矩阵和线性代数
  9. C#开发和调用Web Service
  10. 熟练掌握计算机应用,计算机应用技术专业个人技能怎么写
  11. 当update语句提交后,数据库做了哪些操作?
  12. python 读取网页源码_python获取整个网页源码的方法
  13. GHOST系统封装详细图文教程完整版(二)
  14. 《代码本色:用编程模拟自然系统》作者Daniel Shiffman访谈问题有奖征集
  15. ios-bug.html黑屏重启,iOS12曝重大BUG:iPhone黑屏无法充电!你中招没?
  16. caffe源码 layer分析
  17. php文件上传限制后缀,input file上传文件扩展名限制
  18. pytorch-yolov5_deepsort目标跟踪行人车辆计数
  19. GoPing_多线程图形化ping工具
  20. 公共租赁住房新系统图文教程

热门文章

  1. Docker定制化Python基础镜像
  2. nginx安装、配置文件详解、测试
  3. 使用J-Link打印日志
  4. 知云文献翻译打不开_知云文献翻译 for mac v1.0.1
  5. json和jsonp区别与讲解
  6. 解决微信图片不可引用的问题
  7. MAX31865模块的使用-基于ZigBee_CC2530芯片 PT100测温
  8. 微信小程序 从某个页面直接返回首页
  9. 地铁怎么坐才不能做反_地铁怎么坐,地铁怎么坐才不能做反
  10. 锂离子电池和燃料电池特性介绍