redis设计与实现

本章完全按照《redis设计与实现》该书进行学习和总结http://redisbook.com/

redis中的数据结构包括
简单动态字符串
链表
字典
跳表
整数集合
压缩列表
对象
简单动态字符串
结构:

public class SDSstruct {
    //长度---传统数组要想取得长度需要遍历(节省开销)
    int len;
    //记录空闲空间
    //因为有了记录所以在存储上不需要因为修改而重新分配内存
    //达到预分配内存或者惰性分配内存(节省开销)
    int free;
    //存储空间
    char buf[];
    //C语言中的数组最后一位是空字符串(\n)来判断字符数组结束。
    //因为这个特性,C字符串只能保存文本数据,不能保存图片,视频,压缩等数据
    //而SDS是通过len判断长度而不像C是由\n判断长度结束的
}

预分配策略
当len<1MB;len=free(32len+32free+1空字符串=65)
当len>1MB;free只有1MB(32Mlen+1Mfree+1b空字符串=33MB)

链表
结构:

//链表节点
public class LinkListNodeStruts {
   LinkListNodeStruts pre;
   LinkListNodeStruts next;
   String value;
}
//链表
public class ListStruts {
   LinkListNodeStruts  head;
   LinkListNodeStruts  tail;
   long len;
   public void dup(){};
   public void free(){};
   public void match(){};
}

链表被广泛用于实现redis功能。
字典(map)
map的底层是由hash表实现的
哈希表(散列表)
原理:
哈希表hash table(key,value) 的做法其实很简单,就是把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里。
而当使用哈希表进行查询的时候,就是再次使用哈希函数将key转换为对应的数组下标,并定位到该空间获取value,如此一来,就可以充分利用到数组的定位性能进行数据定位。
因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了“冲突”。
特点:
直接定址
解决冲突
解决冲突之拉链法
上面的方法使用数组实现的,其实很多时候需要使用数组链表来做。开一个数组,数组每个元素都是一个链表。(hash函数选择,针对字符串,整数,排列,具体相应的hash方法。 碰撞处理,一种是open hashing,也称为拉链法;另一种就是closed hashing,也称开地址法,opened addressing。(https://blog.csdn.net/zeb_perfect/article/details/52574915
哈希表会自动收缩和扩展

跳跃表
有序集合的底层实现,每一个节点(node)都保存了一条数据。
Redis中有两个地方用到了跳表
1.有序集合
2.集群节点用在节点内部数据结构
跳跃表-原理及Java实现
https://www.cnblogs.com/acfox/p/3688607.html
Node节点
key value
四个指针top down left right

package com;


import java.util.*;
public class SkipList {
    public Node head;   //头节点
    public Node tail;   //尾结点
    public int h;   //层数
    public int size;    //元素个数
    public Random rand; //每次的随机数用来确定需不需要增加层数
    public SkipList(){
        Node p1 = new Node(Node.tou,0);
        Node p2 = new Node(Node.wei, 0);
        head=p1;
        tail=p2;
        head.setRight(tail);
        tail.setLeft(head);
        h=0;
        size=0;
        rand = new Random();
    }
    public boolean isEmpty(){
        if(size==0){
            return true;
        }
        return false;
    }
    //找到需要插入位置的前一个节点
    public Node findF(String k){
        Node temp;
        temp=head;
        while(true){
            while(temp.getRight().key!=Node.wei&&temp.getRight().key.compareTo(k)<=0){
                /*
                 * 当链表最底层不为空的时候,从当前层向尾部方向开始查找,直到查找temp.getRight的下一个值大于 当前k的值为止,此时temp小于或等于当前k的值
                 *  要插入的位置即为temp之后的位置了
                 */
                temp=temp.getRight();
            }
            if(temp.getDown()!=null){
                temp=temp.getDown();
            }else{
                break;
            }

        }
        return temp;    //找到节点并返回

    }
    public int add(String k, int v){
        Node temp, temp1;
        temp=findF(k);
        int i;  //当前层数
        if(k.equals(temp.getKey())){
            System.out.println("对象属性完全相同无法添加!");
            int a=temp.value;
            temp.value=v;
            return  a;
        }
        temp1=new Node(k,v);
        temp1.setLeft(temp);
        temp1.setRight(temp.getRight());
        temp.getRight().setLeft(temp1);
        temp.setRight(temp1);
        i=0;

        while(rand.nextDouble()<0.5){   //进行随机,是否需要 在上层添加
            if(i>=h){   //若当前层数超出了高度,则需要另建一层
                Node p1 ,p2 ;
                h=h+1;
                p1=new Node(Node.tou,0);
                p2=new Node(Node.wei,0);

                p1.setRight(p2);
                p1.setDown(head);

                p2.setLeft(p1);
                p2.setDown(tail);

                head.setUp(p1);
                tail.setUp(p2);

                head=p1;
                tail=p2;
            }
            while(temp.getUp() == null){
                temp=temp.getLeft();
            }
            temp=temp.getUp();
            Node node=new Node(k,v);
            node.setLeft(temp);
            node.setRight(temp.getRight());
            node.setDown(temp1);

            temp.getRight().setLeft(node);
            temp.setRight(node);
            temp1.setUp(node);

            temp1=node;
            i=i+1;

        }

        size=size+1;
        return  0;
    }
    //节点查找
    public Node find(String k){
        Node temp=head;
        Node node;
        node=temp;
        System.out.println("查找路线"); //用于测试
        while(temp!=null){
            while(node.getRight().key!=Node.wei&&node.getRight().getKey().compareTo(k)<=0){//&&node.getRight().getValue()!=v
                node=node.getRight();
                System.out.print("--->"+node.getKey());
            }

            if(node.getDown()!=null){
                node=node.getDown();
                System.out.print("--->"+node.getKey());
            }else{
                if(node.key.equals(k)){//&&node.getRight().value==v
                    //node.setValue(111111111); //修改
                    System.out.println("--->"+node.getKey());
                    System.out.print("--->"+node.getValue());

                    return node;
                }
                return null;
            }


        }
        return null;
    }
    //节点删除
    public void delNode(String k){  //调用查找函数,删除最底层的某个节点,并把其节点的左右相连,和链表操作一样,只是其上方若有则都需要调整
        Node temp=find(k);
        while(temp!=null){
            temp.getLeft().setRight(temp.getRight());
            temp.getRight().setLeft(temp.getLeft());
            temp=temp.getUp();
        }
    }
    public void print(){
        Node node;
        Node node1=head;


        while(node1!=null){
            int k=0;
            node=node1;
            while(node!=null){
                System.out.print(node.getKey()+"\t");
                k++;
                node=node.getRight();
            }

            System.out.print("\t");
            System.out.print("("+k+")");
            //System.out.print(node.getKey());
            System.out.println();
            //node=node1.getDown();
            node1=node1.getDown();

        }
    }

}
class Node{
    public String key;
    public int value;
    public Node up, down,left , right;
    public static String tou=new String("--头--");
    public static String wei=new String("--尾--");
    public Node(String k, int v){
        this.key=k;
        this.value=v;
        up=down=left=right=null;
    }
    public void setUp(Node up){
        this.up=up;
    }
    public Node getUp(){
        return up;
    }
    public void setDown(Node down){
        this.down=down;
    }
    public Node getDown(){
        return down;
    }
    public void setLeft(Node left){
        this.left=left;
    }
    public Node getLeft(){
        return left;
    }
    public void setRight(Node right){
        this.right=right;
    }
    public Node getRight(){
        return right;
    }
    public void setKey(String k){
        this.key=k;
    }
    public String getKey(){
        return key;
    }
    public void setValue(int v){
        this.value=v;
    }
    public int getValue(){
        return value;
    }

}



//测试类
package com;

public class Test {
    public static void main(String[] args){
        SkipList s = new SkipList();
//      s.add("AAA", 122);
        int i=0;
        for(;i<30;i++){ //随机数字进行测试
            s.add(String.valueOf(i), i);
        }
        s.print();
        System.out.println("\n\n----------\n\n\n");
        if(s.find("22")!=null){ //查找
            System.out.println("\nOK");
        }else{//找不到
            System.out.println("\nfalse");

        }
        s.delNode("0"); //删除
        s.print();
    }
}

整数集合

用于集合中的元素都为整数且元素不多。
结构

public class IntSetStruts {
    //编码
    Long encoding;
    //长度
    Long length;
    //存储容器
    Long contents[];
}

因为有16位。32位。64位的长度所以如果都用64位来存储会造成浪费因此有编码这个字段会生存储空间。
压缩列表
对这个没有太大的兴趣请参考博文
https://blog.csdn.net/men_wen/article/details/70176753

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,172评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,346评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,788评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,299评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,409评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,467评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,476评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,262评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,699评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,994评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,167评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,499评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,149评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,387评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,028评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,055评论 2 352

推荐阅读更多精彩内容