この記事は公式アカウント[DevelopingPigeon]から公開されています!フォローへようこそ!!!
古いルール-姉妹都市都市:
1。辞書
(I.概要
キーと値のペアを格納するために使用される抽象的なデータ構造。キーは値に関連付けることができ、各キーは一意です。C言語には辞書が組み込まれていないため、Redisは独自の辞書実装を構築しており、これはRedisでも広く使用されています。たとえば、Redisデータベースは、辞書を最下層と最下層の1つとして使用して実装されます。ハッシュキーなどのレイヤー実装。
(2)辞書の実現
Redisのディクショナリは、基盤となる実装としてハッシュテーブルを使用します。ハッシュテーブルには複数のハッシュテーブルノードが存在する可能性があり、各ハッシュテーブルノードはキーと値のペアをディクショナリに格納します。
1.ハッシュテーブル
Redisディクショナリで使用されるハッシュテーブルは、dictht構造によって定義されます。
typedef struct dictht{
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
}dictht;
table属性は配列であり、各要素はdictEntry構造体へのポインターです。これは、ハッシュテーブルノードであり、キーと値のペアを保持します。
size属性は、ハッシュテーブルのサイズ、つまりテーブル配列のサイズを記録します。
usedは、ハッシュテーブル内の既存のノードの数を記録します。
sizemask属性の値はsize-1と等しく、これはハッシュ値と一緒に使用され、後で説明するように、テーブル配列内のどのインデックスにキーを配置するかを決定します。
2.ハッシュテーブルノード
ハッシュテーブルノードは、キーと値のペアを保持するdictEntry構造体で表されます。
typedef struct dictEntry{
void *key;
union{
void *val;
uint64_t u64;
int64_t s64;
}v;
struct dictEntry *next;
}dictEntry;
key属性は、キーと値のペアのキーです。
v属性は、キーと値のペアの値であり、ポインターまたは整数、つまり、ユニオンのいずれか1つにすることができます。
次の属性は、別のハッシュテーブルノードへのポインタです。このノードは、同じハッシュ値を持つ複数のキーと値のペアをリンクして、キーの競合の問題を引き起こす可能性があります。
3.辞書
辞書はdict構造によって実装されます
typedef struct dict{
dictType *type;
void *privdata;
dictht ht[2];
int trehashidx;
}dic;
type属性とprivdata属性は、多態的な辞書を作成するために、さまざまなタイプのキーと値のペアに設定されます。
ht属性は2つの項目を含む配列です。各項目はdicthtハッシュテーブルです。通常、ディクショナリはht [0]ハッシュテーブルを使用し、ht [1]はht [0]を再ハッシュする場合にのみ使用されます。
trehashidxは、再ハッシュの現在の進行状況を記録します。再ハッシュが実行されない場合は、-1になります。
(3)ハッシュアルゴリズム
新しいキーと値のペアを辞書に追加するときは、最初にキーに従ってハッシュ値とインデックス値を計算し、次にインデックス値に従って、新しいキーと値のペアを含むハッシュテーブルノードをハッシュテーブル配列に配置します。上記の指定されたインデックス。
ハッシュ値を計算するRedisの方法は、dict-> type-> hashFunction(key)です。ハッシュ値を計算した後、インデックス値は、ハッシュテーブルのsizemask属性とハッシュ値に従って計算されます。
index = hash & dict->ht[x].sizemask;
ht [x]はht [0]またはht [1]にすることができます。再ハッシュがない場合はht [0]になります。再ハッシュが進行中の場合、新しいノードはht [1]に配置され、古いノードは引き続きht [1]。ht[0]にあります。
インデックス値が計算された後、インデックス値はハッシュテーブルノードがハッシュテーブル配列に配置される場所です。0の場合、ht [0] [0]の位置に配置されます。MurmurHash2アルゴリズムが使用されます。ハッシュ値を計算するためにRedisで。
(4)主要な競合の問題
ハッシュテーブル配列内の同じインデックスに2つ以上のキーが割り当てられている場合、これらのキーは競合すると言われます。Redisハッシュテーブルはチェーンアドレス方式を使用してキーの競合の問題を解決し、複数のハッシュテーブルノードは次のポインタを使用して単一リンクリスト。dictEntryノードで構成されるリンクリストにはリンクリストの末尾へのポインタがないため、パフォーマンスのために、新しいハッシュテーブルノードがヘッド補間メソッドによって追加されます。
(5)再ハッシュ
ハッシュテーブルに格納されているキーと値のペアが多すぎるか少なすぎる場合、プログラムはそれに応じてハッシュテーブルのサイズを拡大および縮小し、再ハッシュを介して完了する必要があります。
1.ディクショナリのht [1]ハッシュテーブルにスペースを割り当てるかどうかは、実行する操作と、現在ht [0]に含まれているキーと値のペアの数によって異なります。拡張操作の場合、ht [1]はキーと値のペアの数の2倍以上の最初のn乗です。縮小操作の場合、ht [1]のサイズが最初になります。キーと値のペア以上数値は2の累乗になります。
2. ht [0]からht [1]のすべてのキーと値のペアを再ハッシュします。これは、キーのハッシュ値とインデックスを再計算し、キーと値のペアをht [1]の対応する位置に配置することを意味します。
3.すべての移行が完了したら、ht [0]を解放し、ht [1]をht [0]に設定して、ht [1]に新しい空白のハッシュテーブルを作成します。
ハッシュテーブルの負荷率=ハッシュテーブルに格納されているノードの数/ハッシュテーブルのサイズ
ハッシュテーブルの負荷率が0.1未満の場合、縮小操作が自動的に実行されます。
大規模なハッシュテーブルの場合、計算量が多すぎるため、再ハッシュ操作全体が一元的に実行されるのではなく、複数回、段階的に実行されます。再ハッシュに必要なすべての計算は、辞書の追加、削除、変更、およびクエリ操作に割り当てられます。インクリメント操作はht [1]でのみ行われ、他の操作は2つのハッシュテーブルで同時に実行されます。プログレッシブリハッシュの手順は次のとおりです。
1.辞書がht [0]とht [1]の両方を保持するように、ht [1]にスペースを割り当てます。
2.ディクショナリでインデックスカウンタ変数trehashidxを維持し、0に設定します。これは、再ハッシュを開始することを意味します。
3.辞書を追加、削除、変更、およびチェックするたびに、指定された操作の実行に加えて、trehashidxインデックス内のht [0]のすべてのキーと値のペアがht [1]に再ハッシュされます。
4. ht [0]のすべての移行が完了し、trehashidxが-1に設定されます。