Dictionary and hash table to implement Redis source code

Through the study of "Redis design and implementation", I intend to implement a "Redis source code" as my own learning record.

Students interested in Redis can view another article of mine Make a wheel write a Redis by yourself.

This chapter introduces the dictionary in Redis source code and the implementation of its internal hash table.



Implementation of dictionary dict


API of dict

(1) create a new dictionary

dict dictCreate(dictType type,int hashSize);

(2) find the corresponding node in the hashTable according to the key

dictEntry lookup(dict d,void *key);

(3) add the given key value pair to the dictionary

(if the key already exists in the dictionary, replace the old value with the new value)
bool dictInsert(dict d, void key, void *val);

(4) return the value of the given key

void dictFetchValue(dict d, void *key);

(5) delete the key value pair corresponding to the given key from the dictionary

void dictDelete(dict d, void key);

(6) release the given dictionary and all key value pairs contained in the dictionary

void dictRelease(dict *d);



Header file

#ifndef __DICT_H
#define __DICT_H

//The nodes of hash table are represented by dictEntry structure
//Each dictEntry structure holds a key value
typedef struct dictEntry{
    //key
    void *key;
    //value
    void *value;
    //Point to the next hash table node to form a linked list -- avoid key conflicts
    struct dictEntry *next;
}dictEntry;

//Save a set of functions for manipulating a specific type of key value pair
typedef struct dictType {
    //Function to calculate hash value
    unsigned int (*hashFunction)(void *key,int size);
    //Copy function of key
    void *(*keyDup)(void *key);
    //Function to copy values
    void *(*valDup)(void *obj);
    //Functions of comparison keys
    int (*keyCompare)(void *key1, void *key2);
    //Function to destroy key
    void (*keyDestructor)(void *key);
    //Function to destroy value
    void (*valDestructor)(void *obj);
} dictType;

//Hashtable
typedef struct dictht {
    //Hash table array
    dictEntry **table;
    //Hash table size
    int size;
    //Number of existing nodes in the hash table
    int used;
} dictht;

//Dictionaries
//In fact, a dictionary is another layer of encapsulation for a common hash table
//Added some attributes
typedef struct dict {
    //Type specific function
    dictType *type;
    //Hashtable
    dictht *ht;
} dict;

//Create a new dictionary
//The size of the incoming hash table is required
dict *dictCreate(dictType *type,int hashSize);
//Find the corresponding node in hashTable according to key
dictEntry* lookup(dict *d,void *key);
//Add the given key value pair to the dictionary
//Add the given key value pair to the dictionary. If the key already exists in the dictionary,
//Then replace the original value with the new value
bool dictInsert(dict *d, void *key, void *val);
//Returns the value of the given key
void *dictFetchValue(dict *d, void *key);
//Delete the key value pair corresponding to the given key from the dictionary
void dictDelete(dict *d, void *key);
//Release the given dictionary and all key value pairs contained in the dictionary
void dictRelease(dict *d);

#endif



Implementation of dict API

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dict.h"

//Size of hash table
#define HASHSIZE 10

//Define the set of functions that operate on the hash table
//Function to calculate hash value
unsigned int myHashFunction(void *key,int size){
    char* charkey=(char*)key;
    unsigned int hash=0;
    for(;*charkey;++charkey){
        hash=hash*33+*charkey;
    }
    return hash%size;
}
//Copy function of key
void *myKeyDup(void *key){
    return key;
}
//Function to copy values
void *myValDup(void *obj){
    return obj;
}
//Functions of comparison keys
int myKeyCompare(void *key1, void *key2){
    char*charkey1=(char*)key1;
    char*charkey2=(char*)key2;
    return strcmp(charkey1,charkey2);
}
//Function to destroy key
void myKeyDestructor(void *key){
    //free(key);
}
//Function to destroy value
void myValDestructor(void *obj){
    //free(obj);
}

//Create a new dictionary
dict *dictCreate(dictType *type,int hashSize){
    dict* d=(dict*)malloc(sizeof(dict));
    //A specific set of functions related to hashTable operations
    if(type==NULL){
        printf("PIG Redis WARNING : Type is NULL.\n");
    }
    d->type=type;
    //Hash table initialization
    d->ht=(dictht*)malloc(sizeof(dictht));
    d->ht->size=hashSize;
    d->ht->used=0;
    d->ht->table=(dictEntry**)malloc(sizeof(dictEntry*)*hashSize);
    //All nodes are set to NULL
    for(int i=0;i<hashSize;i++){
        d->ht->table[i]=NULL;
    }
    return d;
}

//Find the corresponding node in hashTable according to key
dictEntry* lookup(dict *d,void *key){
    dictEntry* node;
    //The subscript corresponding to the key in the hashTable
    unsigned int index;
    index=d->type->hashFunction(key,d->ht->size);
    for(node=d->ht->table[index];node;node=node->next){
        if(!(d->type->keyCompare(key,node->key))){
            return node;
        }
    }
    return NULL;
}

//Add the given key value pair to the dictionary
bool dictInsert(dict *d, void *key, void *val){
    unsigned int index;
    dictEntry* node;
    if(!(node=lookup(d,key))){
        index=d->type->hashFunction(key,d->ht->size);
        node=(dictEntry*)malloc(sizeof(dictEntry));
        if(!node)return false;
        node->key=d->type->keyDup(key);
        node->next=d->ht->table[index];
        d->ht->table[index]=node;
    }
    //If it exists, modify its corresponding value value directly
    node->value=d->type->valDup(val);
    return true;
}

//Returns the value of the given key
void *dictFetchValue(dict *d, void *key){
    unsigned int index;
    dictEntry* node;
    //This node cannot be found
    if(!(node=lookup(d,key))){
        return NULL;
    }
    return node->value;
}

//Delete the key value pair corresponding to the given key from the dictionary
void dictDelete(dict *d, void *key){
    dictEntry* node;
    dictEntry* temp;
    //The subscript corresponding to the key in the hashTable
    unsigned int index;
    index=d->type->hashFunction(key,d->ht->size);
    node=d->ht->table[index];
    //key is the same.
    if(!(d->type->keyCompare(key,node->key))){
        d->ht->table[index]=node->next;
        d->type->keyDestructor(node->key);
        d->type->valDestructor(node->value);
        free(node);
        return;
    }
    temp=node;
    node=node->next;
    while(node){
        if(!(d->type->keyCompare(key,node->key))){
            temp->next=node->next;
            d->type->keyDestructor(node->key);
            d->type->valDestructor(node->value);            
            free(node);
            return;
        }
        temp=node;
        node=node->next;
    }
    return;
}
//Release the given dictionary and all key value pairs contained in the dictionary
void dictRelease(dict *d){
    dictEntry* node;
    dictEntry* temp;
    for(int i=0;i<d->ht->size;i++){
        node=d->ht->table[i];
        //printf("%d\n",i);
        while(node){
            char* t=(char*)node->value;
            //printf("%s\n",t);
            temp=node;
            node=node->next;
            d->type->keyDestructor(temp->key);
            d->type->valDestructor(temp->value);
            free(temp);
        }
    }
    free(d->ht);
    free(d->type);
    free(d);
}

/*int main(){
    dictType*type=(dictType*)malloc(sizeof(dictType));
    type->hashFunction=myHashFunction;
    type->keyDup=myKeyDup;
    type->valDup=myValDup;
    type->keyCompare=myKeyCompare;
    type->keyDestructor=myKeyDestructor;
    type->valDestructor=myValDestructor;
    dict* d=dictCreate(type,HASHSIZE);
    
    char*key1="sss";
    char*value1="111";
    bool result=dictInsert(d,key1,value1);
    if(result){
        printf("insert1 success\n");
    }else{
        printf("insert1 fail\n");
    }

    char*key2="3sd";
    char*value2="ddd";
    result=dictInsert(d,key2,value2);
    if(result){
        printf("insert2 success\n");
    }else{
        printf("insert2 fail\n");
    }

    char*key3="ddds";
    char*value3="1ss";
    result=dictInsert(d,key3,value3);
    if(result){
        printf("insert3 success\n");
    }else{
        printf("insert3 fail\n");
    }
    
    char *value4=(char*)dictFetchValue(d,key3);
    printf("---%s\n",value4);

    dictDelete(d,key3);
    value4=(char*)dictFetchValue(d,key3);
    printf("---%s\n",value4);

    dictRelease(d);
    system("pause");
    return 0;
}*/



Tags: C++ Redis

Posted on Tue, 03 Dec 2019 10:09:10 -0500 by ahzulfi