美文网首页
Redis io抽象层

Redis io抽象层

作者: taj3991 | 来源:发表于2020-01-14 14:22 被阅读0次

    Redis中涉及到多种io,如socket与file,为了统一对它们的操作,redis设计了一个抽象层,即rio,使用rio可以实现将数据写入到不同的底层io,但是接口相同。rio的实现在rio.h与rio.c源文件中,支持内存、文件、socket集合三类底层io。

    1. struct rio

    struct rio中声明了统一的io操作接口,并且包含一个底层io对象的union结构。使用不同的底层io初始化rio实例后,调用rio的抽象接口即会调用对应底层io的实现。以面向对象的思想即是,rio为抽象类,它拥有三个子类:buffer、file及fdset,这三个子类实现了抽象类声明的接口。使用者可以使用它们的父类rio进行编程,实现多态性。

    以下是struct rio中抽象接口的声明(此处省略了一些其它的成员):

    struct _rio {
        /* Backend functions.
         * Since this functions do not tolerate short writes or reads the return
         * value is simplified to: zero on error, non zero on complete success. */
        size_t (*read)(struct _rio *, void *buf, size_t len);
        size_t (*write)(struct _rio *, const void *buf, size_t len);
        off_t (*tell)(struct _rio *);
        int (*flush)(struct _rio *);
        /* The update_cksum method if not NULL is used to compute the checksum of
         * all the data that was read or written so far. The method should be
         * designed so that can be called with the current checksum, and the buf
         * and len fields pointing to the new block of data to add to the checksum
         * computation. */
        void (*update_cksum)(struct _rio *, const void *buf, size_t len);
    
      ...
    /* Backend-specific vars. */
      ...
    };
    

    每一个底层对象都需要实现它需要支持的接口,实例化rio时,rio结构中的函数指针将指向底io的实现。Redis是C语言实现,因此针对 三个底层io声明了三个对应的初始化函数:

    void rioInitWithFile(rio *r, FILE *fp);
    void rioInitWithBuffer(rio *r, sds s);
    void rioInitWithFdset(rio *r, int *fds, int numfds);
    

    这三个函数将初始化rio实例中的函数指针为它对应的抽象接口实现,并初始化union结构指向正确的底层io对象。

    注意:rio接口中虽然声明了write操作与read操作,但是redis中仅将它们用于单向操作,即一个rio实例或者使用write操作,或者使用read操作,同一个rio实例不能既读又写。*

    2. buffer

    以buffer为底层io的rio实例,write操作将参数buf中的数据copy到一个sds中(redis的字符串实现)。反之,它的read操作将会从一个sds中读取数据到参数buf指向的地址中。

    抽象接口不支持seek操作,因此写操作仅能append,而读操作也只能从当前位置读数据。buffer对象的结构声明如下:

    /* In-memory buffer target. */
            struct {
                sds ptr;
                off_t pos;
            } buffer;
    

    这里的pos记录了读写操作在buffer中的当前位置。

    3. file

    以file为底层io的rio实例,write操作将参数buf中的数据写入到文件中,而read操作则将file中的数据读到参数buf指向的内存地址中。file对象的抽象接口实现只需要简单的调用c语言的库函数即可。

    同样由于抽象接口未声明seek操作,它的具体实现也没有实现seek操作。file对象的结构声明如下:

     /* Stdio file pointer target. */
            struct {
                FILE *fp;
                off_t buffered; /* Bytes written since last fsync. */
                off_t autosync; /* fsync after 'autosync' bytes written. */
            } file;
    

    4. fdset

    以fdset为底层io的rio实例可以同时将数据向多个目标写,在redis中主要用作master向它的多个slave发送同步数据,即使用fdset的write操作可以将一份数据向多个socket发送。对fdset的抽象大大地简化了redis的master向它的多个slave发送同步数据的 io操作

    fdset不支持read操作。此外,它使用了类似buffer的一个sds实例作为缓存,数据首先被写入到该缓存中,当缓存中的数据超过一定数量,或者调用了flush操作,再将缓存中的数据发送到所有的socket中。fdset的结构声明如下:

     /* Multiple FDs target (used to write to N sockets). */
            struct {
                int *fds;       /* File descriptors. */
                int *state;     /* Error state of each fd. 0 (if ok) or errno. */
                int numfds;
                off_t pos;
                sds buf;
            } fdset;
    

    fds即所有的目标socket的文件描述符集合,state记录了这些文件描述符的状态(是否发生写错误),numfds记录了集合的大小,buf为缓存,pos代表buf中下一个应该发送的数据的位置。

    原文

    https://www.cnblogs.com/yang-zd/p/11626738.html

    相关文章

      网友评论

          本文标题:Redis io抽象层

          本文链接:https://www.haomeiwen.com/subject/aqqaactx.html