PHP Yac cache 源码学习笔记
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 = 1yac.keys_memory_size = 4M ; 4M can get 30K key slots, 32M can get 100K key slotsyac.values_memory_size = 64Myac.compress_threshold = -1yac.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; //valueunsigned 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
PHP Yac cache 源码学习笔记相关推荐
- Java多线程之JUC包:Semaphore源码学习笔记
若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/go2sea/p/5625536.html Semaphore是JUC ...
- RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的?
RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 文章目录 RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 前言 项目 ...
- Vuex 4源码学习笔记 - 通过Vuex源码学习E2E测试(十一)
在上一篇笔记中:Vuex 4源码学习笔记 - 做好changelog更新日志很重要(十) 我们学到了通过conventional-changelog来生成项目的Changelog更新日志,通过更新日志 ...
- Vuex 4源码学习笔记 - Vuex是怎么与Vue结合?(三)
在上一篇笔记中:Vuex源码学习笔记 - Vuex开发运行流程(二) 我们通过运行npm run dev命令来启动webpack,来开发Vuex,并在Vuex的createStore函数中添加了第一个 ...
- jquery源码学习笔记三:jQuery工厂剖析
jquery源码学习笔记二:jQuery工厂 jquery源码学习笔记一:总体结构 上两篇说过,query的核心是一个jQuery工厂.其代码如下 function( window, noGlobal ...
- 雷神FFMpeg源码学习笔记
雷神FFMpeg源码学习笔记 文章目录 雷神FFMpeg源码学习笔记 读取编码并依据编码初始化内容结构 每一帧的视频解码处理 读取编码并依据编码初始化内容结构 在开始编解码视频的时候首先第一步需要注册 ...
- Apache log4j-1.2.17源码学习笔记
(1)Apache log4j-1.2.17源码学习笔记 http://blog.csdn.net/zilong_zilong/article/details/78715500 (2)Apache l ...
- Vuex 4源码学习笔记 - 通过dispatch一步步来掌握Vuex整个数据流(五)
在上一篇笔记中:Vuex 4源码学习笔记 - Store 构造函数都干了什么(四) 我们通过查看Store 构造函数的源代码可以看到主要做了三件事情: 初始化一些内部变量以外 执行installMod ...
- JDK源码学习笔记——Integer
一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...
最新文章
- 二元偏导数存在的条件_高等数学入门——高阶偏导数的概念和计算
- http 请求 与其同步与异步请求的通透讲解
- php 运算验证码类,php 数学运算验证码实现代码
- 波纹扩散_C4D_动画amp;RS波纹扩散效果J_014
- Python网络编程(1)-socket
- eclispe快捷键
- 凸包 poj 1113
- 自然语言处理实践Task2
- SAP License:如何学好SAP BASIS
- Prototype使用$F()函数
- OA打造企业“最强大脑”
- QT之Tcp数据发送测试工具
- 十大经典算法及其优化
- vue图片压缩与批量上传
- 【Hexo】hexo在文章中添加图片
- ARM_Linux开发之TFTP应用
- 哈利波特魔法游戏(原创)
- 图灵机器人之Python实现
- 目前常见的大数据分析软件有哪些?
- 数据结构 | 3.树与二叉树
热门文章
- 计算机可以调环境工程吗,地理学被调剂到环境科学/环境工程专业,值得去么?...
- tree(陈立杰)[国家集训队2012]
- echarts 饼图调用高亮示例 dispatchAction
- c语言表达式和逻辑表达式是,C语言中关系表达式和逻辑表达式的值是什么
- So Easy!7000元Scrum认证课1元抢~
- 史上最全YYModel的使用详解
- YYModel V1.0.4源码解析
- 8年测试开发,写给1-3年功能测试的几点建议,满满硬货指导
- Java——字符串类实验
- 中国剩余定理matlab程序,中国剩余定理即孙子定理的五种解法