redis:stringタイプの原理と実現
2377 ワード
redisはkey-valueデータベースとしてstringが基本データ型である.
redisのすべてのkeysは文字列タイプであり、文字列タイプもvaluesの基本データタイプである.他のより複雑なデータ型であるlists,sets,sorted sets,hashesも文字列を使用して実現されています.
redis stringデータ型の実現はsdsに含まれる.c(sds、すなわちSimple Dynamic Strings、単純な動的文字列)にある.C言語構造体sdshdrはsds.hで宣言され、redis stringタイプを表します.
文字配列bufは実際の文字列を格納する.
len変数は文字列の長さを保存し、文字列の長さを取得する時間の複雑さはO(1)である.
free変数はbufで利用可能な空間を格納する.
lenとfreeはbuf文字配列のメタ情報を保存した. redis文字列 を作成する
sds.hではsdsという新しいデータ型が定義されていますが、実は文字列ポインタです.
sds.cで定義した
redis stringはsdshdrタイプの変数ですが、この関数は文字列ポインタを返します.
これは小さなテクニックです.ここで説明します.
この関数はstruct sdshdrタイプ変数を作成し、len、free、bufにメモリ領域を割り当てます.
sdsnewlenの作成に成功した後、
sdsnewlenはsh->bufを呼び出し元に返します.
では、shが指すredis stringを解放する必要がある場合は、どうすればいいのでしょうか.
shを指すポインタが必要ですが、sh->bufを指すポインタが必要です.
sh->bufからshを指すポインタをもらえますか?
いいですよ.ポインタによる演算.以上のASCIIプロットから,sh->bufから2つのlong型サイズを減算するとshを指すポインタが得られることが分かる.2つのlong型の大きさは
redis stringの実装はインタフェースの後ろに隠されており、このインタフェースは文字列ポインタのみを受け入れる.redis stringのユーザは,その具体的な実装に関心を持つ必要はなく,文字列ポインタと見なせばよい.
原文:http://redis.io/topics/internals-sds
redisのすべてのkeysは文字列タイプであり、文字列タイプもvaluesの基本データタイプである.他のより複雑なデータ型であるlists,sets,sorted sets,hashesも文字列を使用して実現されています.
redis stringデータ型の実現はsdsに含まれる.c(sds、すなわちSimple Dynamic Strings、単純な動的文字列)にある.C言語構造体sdshdrはsds.hで宣言され、redis stringタイプを表します.
struct sdshdr {
long len;
long free;
char buf[];
};
文字配列bufは実際の文字列を格納する.
len変数は文字列の長さを保存し、文字列の長さを取得する時間の複雑さはO(1)である.
free変数はbufで利用可能な空間を格納する.
lenとfreeはbuf文字配列のメタ情報を保存した.
sds.hではsdsという新しいデータ型が定義されていますが、実は文字列ポインタです.
typedef char *sds;
sds.cで定義した
sdsnewlen
関数は、新しい文字列を作成するために使用されます.sds sdsnewlen(const void *init, size_t initlen) {
struct sdshdr *sh;
sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
#ifdef SDS_ABORT_ON_OOM
if (sh == NULL) sdsOomAbort();
#else
if (sh == NULL) return NULL;
#endif
sh->len = initlen;
sh->free = 0;
if (initlen) {
if (init) memcpy(sh->buf, init, initlen);
else memset(sh->buf,0,initlen);
}
sh->buf[initlen] = '\0';
return (char*)sh->buf;
}
redis stringはsdshdrタイプの変数ですが、この関数は文字列ポインタを返します.
これは小さなテクニックです.ここで説明します.
sdsnewlen
を使用して文字列「redis」を作成するとします.sdsnewlen("redis", 5);
この関数はstruct sdshdrタイプ変数を作成し、len、free、bufにメモリ領域を割り当てます.
struct sdshdr *sh;
sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
sdsnewlenの作成に成功した後、
の構造を持つredis stringが得られた.-----------
|5|0|redis|
-----------
^ ^
sh sh->buf
sdsnewlenはsh->bufを呼び出し元に返します.
では、shが指すredis stringを解放する必要がある場合は、どうすればいいのでしょうか.
shを指すポインタが必要ですが、sh->bufを指すポインタが必要です.
sh->bufからshを指すポインタをもらえますか?
いいですよ.ポインタによる演算.以上のASCIIプロットから,sh->bufから2つのlong型サイズを減算するとshを指すポインタが得られることが分かる.2つのlong型の大きさは
struct sdshdr
の大きさである.sdslen
関数がどのように機能しているかを見てみましょう.size_t sdslen(const sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
return sh->len;
}
このテクニックを理解すると、sdsを理解しやすくなります.cの他の関数.redis stringの実装はインタフェースの後ろに隠されており、このインタフェースは文字列ポインタのみを受け入れる.redis stringのユーザは,その具体的な実装に関心を持つ必要はなく,文字列ポインタと見なせばよい.
原文:http://redis.io/topics/internals-sds