对于redis的基本数据结构,经过一个多星期的分析大概是明了了。接下来根据计划是分析t_前缀的大量的接口函数。这里面就比底层数据更加接近用户的逻辑代码了。其实本人比较期待的后面集群,服务器等这些代码的实现。话不多说,马上来分析一下吧。
这部分的代码并没有头文件。直接一个c文件里面包含了所有的函数,我经过整理后,根据比较合适的阅读顺序来发每一个函数吧。这部分的函数主要做的工作都是,通过前面的robj结构体,获取key-value,以及添加删除等操作的qpi。
首先为查找value的操作。对于hash表的存储,redis的策略是使用dict或者ziplist来存储。所以就会出现两种情况,根据编码模式调用不同的取值函数。
/* Higher level function of hashTypeGet*() that returns the hash value
* associated with the specified field. If the field is found C_OK
* is returned, otherwise C_ERR. The returned object is returned by
* reference in either *vstr and *vlen if it's returned in string form,
* or stored in *vll if it's returned as a number.
*
* If *vll is populated *vstr is set to NULL, so the caller
* can always check the function return by checking the return value
* for C_OK and checking if vll (or vstr) is NULL. */
int hashTypeGetValue(robj *o, sds field, unsigned char **vstr, unsigned int *vlen, long long *vll) {
//该函数根据编码模式,从上一次分析的封装对象中,获取与field对应的值。
//redis是key-value的nosql数据库,获取每一个value必定存在其key
if (o->encoding == OBJ_ENCODING_ZIPLIST) {// 根据类型调用相应的函数
*vstr = NULL;
if (hashTypeGetFromZiplist(o, field, vstr, vlen, vll) == 0)
return C_OK;
} else if (o->encoding == OBJ_ENCODING_HT) {
sds value;
if ((value = hashTypeGetFromHashTable(o, field)) != NULL) {
*vstr = (unsigned char*) value;
//此时vstr存储对应的数据
*vlen = sdslen(value);
//vlen存储数据的长度。
return C_OK;
}
} else {
serverPanic("Unknown hash encoding");
}
return C_ERR;
}
下面分别是两种编码结构的具体实现,主要是调用了其结构提供的api。
/* Get the value from a ziplist encoded hash, identified by field.
* Returns -1 when the field cannot be found. */
//如应为所所找到的话返回到vll中或者vstr中,根据类型进行选择
//若没有找到则直接返回-1,研究源码不要太过深究,重在数据结构与设计思路。
//太过深究,时间花太多,反而没有兴致了。
//对于太过复杂的问题就应该不求甚解的学习方式
int hashTypeGetFromZiplist(robj *o, sds field,
unsigned char **vstr,
unsigned int *vlen,
long long *vll)
{
unsigned char *zl, *fptr = NULL, *vptr = NULL;
int ret;
serverAssert(o->encoding == OBJ_ENCODING_ZIPLIST);
zl = o->ptr;
fptr = ziplistIndex(zl, ZIPLIST_HEAD);
//ziplist_head 为 0 找到的为第一个元素的地址
//下面对于ziplist的一顿操作,都是根据field值找到该元素。
if (fptr != NULL) {
fptr = ziplistFind(fptr, (unsigned char*)field, sdslen(field), 1);
//发现这个list也是以key-value的方式进行存储,那么就需要设置skip数为1
//那么相当于两个两个对数据进行遍历。
//找到key的值后,value的值就是next。
//下面调用ziplistNext的原因迎刃而解。
if (fptr != NULL) {
/* Grab pointer to the value (fptr points to the field) */
vptr = ziplistNext(zl, fptr);
//这边的指向下个元素,原因也不懂,可能是由于没有认真看ziplist中的所有函数所造成的。
serverAssert(vptr != NULL);
}
}
if (vptr != NULL) {
ret = ziplistGet(vptr, vstr, vlen, vll);
serverAssert(ret);
return 0;
}
return -1;
}
/* Get the value from a hash table encoded hash, identified by field.
* Returns NULL when the field cannot be found, otherwise the SDS value
* is returned. */
sds hashTypeGetFromHashTable(robj *o, sds field) {
dictEntry *de;
//dict就更加好理解了
//直接调用dictFind找出元素,并且获取其值,以sds(字符串)的方式返回
serverAssert(o->encoding == OBJ_ENCODING_HT);
de = dictFind(o->ptr, field);
if (de == NULL) return NULL;
return dictGetVal(de);
}
通过查找返回一个robj结构体,调用前面的查找函数。
/* Like hashTypeGetValue() but returns a Redis object, which is useful for
* interaction with the hash type outside t_hash.c.
* The function returns NULL if the field is not found in the hash. Otherwise
* a newly allocated string object with the value is retur