Jack:redis的数据是怎么存储到数据文件的呢?
我:你看一下rdb.c里的int rdbSave(char *filename) {...}函数。这个函数是redis存储的核心函数。你从这里能看出什么呢?
Jack:传入的参数是一个文件名,所以redis的数据存储是以文件为单位的,而不是以数据库block为单位的。
我:是的。那,为什么redis的数据存储不已文件为单位,而采用以数据库block为单位的方式呢?
Jack:不知道。
我:你回忆一下《redis源代码分析——内存管理与数据类型》,里面说过,redis的内存管理并没有采用Oracle两条链表的经典模式,而是采用了HASH TABLE的方式。在Oracle的两条链表里,挂的是buffer。一个buffer对应一个数据库block。redis既然没有挂buffer的地方又怎么会有block呢?
Jack:嗯。明白了。
我:另外,既然要存储数据,就必须要从db里取数据,为什么这个函数的参数没有db相关的信息呢?
Jack:额~你说说吧。
我:因为DB的相关信息在一个巨无霸全局变量里——server.db。它写的过程如下。
1、if (fwrite("REDIS0002",9,1,fp) == 0) goto werr;
2、 if (rdbSaveType(fp,REDIS_SELECTDB) == -1) goto werr;
3、if (rdbSaveObject(fp,o) == -1) goto werr;(这里需要先判断这个key的object是什么类型的)
4、重复第3部分,直到一个数据库的key都被写完。
5、fflush(fp);fsync(fileno(fp));fclose(fp);
你看下,在这个过程中,最关键的是什么?
Jack:最关键的是fwrite()函数,以及rdbSaveObject(fp,o)函数。
我:这里面有什么dump吗?
Jack:没有。
我:所以,我感到很难理解,当聊到数据块结构解析的时候,你会提到dump。所以,你需要做的是,回头去看《Unix环境高级编程》,那才是王道。里面都对二进制文件write()的详细说明。
Jack:好的。另外,我想了解下,rdbSaveObject()这个函数的关键是什么呢?
我:int rdbSaveObject(FILE *fp, robj *o) {...},这样明白了吧?
Jack:不是太明白。
我:看来你不是一个合格的程序猿,一个合格的程序猿是可以从一个函数定义里看出这个函数的精髓的。而它的精髓就在于robj *o,你思考一下也就明白了。
Jack:那我如果要写一个Oracle的dul,需要思考些什么呢?
我:你觉得呢?
Jack:1、知道Oracle的block是结构体定义是什么样子的。2、破译它的数据类型存储。3、整合出逻辑。
我:是的。要搞到Oracle的block的结构体定义大概有两种方法。1、从Oracle内部的朋友那里搞到internal的资料(不过,不一定能成功)。2、自己破解。
Jack:如何破解呢?
我:不想告诉你。
Jack:为什么要破译Oracle的数据类型存储呢?
我:你看下int rdbSaveObject(FILE *fp, robj *o) {...}就明白了。如果你不看,我怎么说都没有用。
Jack:了解了。
我:这三点里,最难的是第2点,工作量最大的是第3点。感兴趣就去写一个吧。