PHP Yac cache 源码学习笔记
2017-02-04 16:26
288 查看
YAC 源码学习笔记
本文地址http://blog.csdn.net/fanhengguang_php/article/details/54863955
config.m4
检测系统共享内存支持情况
通过autoconf语法AC_TRY_RUN
AC_DEFINE语法进行以下检查
是否支持system v ipc 共享内存
是否支持mmap MAP_ANON 共享内存
是否支持mmap(“/dev/zero”)共享内存
代码示例
AC_TRY_RUN([ #include <sys/types.h> #include <sys/wait.h> #include <sys/ipc.h> #include <sys/shm.h> #include <unistd.h> #include <string.h> int main() { //somthing } ],dnl AC_DEFINE(HAVE_SHM_IPC, 1, [Define if you have SysV IPC SHM support]) msg=yes,msg=no,msg=no)
模块初始化MINIT阶段
读取php.ini 关于key、value 内存等设置
yac.enable = 1 yac.keys_memory_size = 4M ; 4M can get 30K key slots, 32M can get 100K key slots yac.values_memory_size = 64M yac.compress_threshold = -1 yac.enable_cli = 0 ; whether enable yac with cli, default 0
缓存空间空间初始化
缓存空间初始化。根据当前系统的情况, 分别选择使用以下方式进行内存的申请、初始化mmap方式
shm方式
filemaping方式
具体可参见yac/storage/allocator/目录下的createfilemap.c ,mmap.c, shm.c 中的create_segments 方法
初始化Yac类
注册yac类yac类 _construct方法
Yac::__construct([string $prefix])
zend_update_property_str(yac_class_ce, getThis(), ZEND_STRL(YAC_CLASS_PROPERTY_PREFIX), prefix);更新缓存前缀
yac类 set方法
将key => value 的映射存储到缓存中, 函数原型:Yac::set($key, $value[, $ttl]) Yac::set(array $kvs[, $ttl])
<?php $yac = new Yac(); $yac->set("foo", "bar"); $yac->set( array( "dummy" => "foo", "dummy2" => "foo", ) ); ?>
value归一化&压缩
对于不同类型的value(int, bool, long, double, string, constant等) 进行归一化。 统一归一化为字符串, 并进行压缩处理以
$yac->set("foo", "bar");为例, 写cache的操作步骤如下:
将prefix 与原始key链接在一起, 作为新的key。 并判断新key是否超过48个字符,超过则失败
对于有value 为 null, bool , long, double 类型, 直接将对应的数字类型转换为字符串类型
对于value为string类型 or constant类型, 如果value字符串长度超过1<<20后, 利用fastlz方法进行字符串压缩处理
对于array 或者object类型的value, 调用php serializer 方法, 或者利用msgpack方法进行序列化, 并进行压缩处理
cache更新 yac_storage_update
yac key, value 的结构如下:typedef struct { unsigned long h; //key的hash值 unsigned long crc; //value的crc校验码 unsigned int ttl; //过期时间 unsigned int len; //key的长度 unsigned int flag; //value类型,字符串、整形、等等 unsigned int size; //此key 对应 的value 的长度 yac_kv_val *val; //value unsigned char key[YAC_STORAGE_MAX_KEY_LEN]; } yac_kv_key; typedef struct { unsigned long atime; unsigned int len; char data[1]; } yac_kv_val;
通过MurmurHash2 算法计算key的hash值
通过hash值找到对应的slots段的起始位置, 即:一个
yac_kv_key指针
如果此slot的value为空,那么说明之前没有存储过该key, 将执行add操作
如果value 值非空并且hash值相同&key长度相同&key完全一样, 那么说明, 此key之前已经存储过了,将执行update操作。
对此slot对应的value计算crc, 与slot中的crc对比, 判断value是否合法
根据原来value的存储空间大小与新value的size来重新分配内存,更新过期时间, 重新计算crc校验码
如果hash值不同或者key值不一致,说明当前slot,并不是数据存储的位置,
利用times33算法计算hash值, 并根据hash值找到对应的卡槽,进行插入数据
如果所有卡槽都满了, 则根据过期时间剔除一个卡槽, 将数据插入
yac类 get方法
读取key的value值函数原型:Yac::get(array|string $key)
<?php $yac = new Yac(); $yac->set("foo", "bar"); $yac->set( array( "dummy" => "foo", "dummy2" => "foo", ) ); $yac->get("dummy"); $yac->get(array("dummy", "dummy2")); ?>
具体实现参见
static zval * yac_get_impl(zend_string *prefix, zend_string *key, uint32_t *cas, zval *rv)方法
yac_get_impl
方法
将prefix 与key连接为新的key调用
yac_storage_find方法取得value值, 从内存中根据key查找value, 具体做法与set方法基本一致,
MurmurHash2算法计算key hash值, 并找到相应的slots内存位置
如果找不到再利用times33算法计算hash 在后面继续查找
找到相应slot位置后, 判断value是否过期, 判断crc校验码是否一致。
根据value的flag类型将value还原为特定的类型(null, bool, long, double等等)
switch ((flag & YAC_ENTRY_TYPE_MASK)) { case IS_NULL: if (size == sizeof(int)) { ZVAL_NULL(rv); } efree(data); break; case IS_TRUE: if (size == sizeof(int)) { ZVAL_TRUE(rv); } efree(data); break; case IS_FALSE: if (size == sizeof(int)) { ZVAL_FALSE(rv); } efree(data); break; case IS_LONG: if (size == sizeof(long)) { ZVAL_LONG(rv, *(long*)data); } efree(data); break;
对于字符串或者CONSTANT类型, 利用fastlz算法进行解压缩
case IS_STRING: case IS_CONSTANT: { if ((flag & YAC_ENTRY_COMPRESSED)) { size_t orig_len = ((uint32_t)flag >> YAC_ENTRY_ORIG_LEN_SHIT); char *origin = emalloc(orig_len + 1); uint32_t length; length = fastlz_decompress(data, size, origin, orig_len); ZVAL_STRINGL(rv, origin, length); efree(origin); efree(data); } else { ZVAL_STRINGL(rv, data, size); efree(data); } } break;
对于ARRAY OR OBJECT 类型进行先进性解压缩 在用unserializer
yac_serializer_php_unpack操作转换为对象或数组
case IS_OBJECT: length = fastlz_decompress(data, size, origin, rv = yac_serializer_php_unpack(data, size, &msg, rv);
更多内容可参考鸟哥博客 http://www.laruence.com/2013/03/18/2846.html
相关文章推荐
- [源码学习] -- yii2源码学习笔记(四) -- 继续了解组件Component.php
- CI框架源码学习笔记4——Benchmark.php
- [源码学习] -- yii2源码学习笔记(五) -- Event.php
- CI框架源码学习笔记2——Common.php
- CI框架源码学习笔记6——Config.php
- PHP学习笔记 第二讲 PHP的数据类型 源码调试
- CI框架源码学习笔记3——Log.php
- php源码学习笔记之一
- CI框架源码学习笔记7——Utf8.php
- CI框架源码学习笔记1——index.php
- PHP源码学习笔记
- CI框架源码学习笔记5——Hooks.php
- PHP学习笔记(1)----运行环境的建立[原创]
- php学习笔记--php常用函数及其应用(未完成)
- Struts 源码学习笔记
- php学习笔记2—(字符串和注释)
- php学习笔记(1)
- linux 学习笔记 - php 环境安装与配置
- php学习笔记:php中的数组
- PHP and Web Services 学习笔记