Redis Clusterの実装-clusterメッセージの受信とパケット化
4261 ワード
READイベントに対するclusterReadHandlerプロセッサの主な仕事はcluster busで受信したデータを解析してメッセージをパケット化し、メッセージを処理することであるが、メッセージのパケット化についてはまずメッセージ構造を理解する必要があり、Redis Clusterノード間で通信するメッセージ構造は以下のように定義される.
上の構造からメッセージパケットが見え、主に上位8バイトを解析し、それぞれ:-char sig[4];//メッセージ署名、clusterメッセージの場合、文字シーケンスRCmb-uint 32_に固定t totlen;//メッセージの全長他の構造メンバーは、メッセージを処理する際に使用され、メッセージ処理の流れを説明する際に分析されます.
typedef struct {
char sig[4]; /* Siganture "RCmb" (Redis Cluster message bus). */
uint32_t totlen; /* Total length of this message */
uint16_t ver; /* Protocol version, currently set to 0. */
uint16_t notused0; /* 2 bytes not used. */
/* Message type, :PING, PONG, CLUSTERMSG_TYPE_* */
uint16_t type;
uint16_t count; /* Only used for some kind of messages. */
uint64_t currentEpoch; /* The epoch accordingly to the sending node. */
uint64_t configEpoch; /* The config epoch if it's a master, or the last
epoch advertised by its master if it is a
slave. */
uint64_t offset; /* Master replication offset if node is a master or
processed replication offset if node is a slave. */
// , NodeID , : 123ed65d59ff22370f2f09546f410d31207789f6
char sender[REDIS_CLUSTER_NAMELEN]; /* Name of the sender node */
// slots bits
unsigned char myslots[REDIS_CLUSTER_SLOTS/8];
// slave , slaveof master ID
char slaveof[REDIS_CLUSTER_NAMELEN];
char notused1[32]; /* 32 bytes reserved for future usage. */
uint16_t port; /* Sender TCP base port */
uint16_t flags; /* Sender node flags */
// cluster , :REDIS_CLUSTER_OK, REDIS_CLUSTER_FAIL ...
unsigned char state; /* Cluster state from the POV of the sender */
unsigned char mflags[3]; /* Message flags: CLUSTERMSG_FLAG[012]_... */
//
// clusterMsgData
union clusterMsgData data;
} clusterMsg;
上の構造からメッセージパケットが見え、主に上位8バイトを解析し、それぞれ:-char sig[4];//メッセージ署名、clusterメッセージの場合、文字シーケンスRCmb-uint 32_に固定t totlen;//メッセージの全長他の構造メンバーは、メッセージを処理する際に使用され、メッセージ処理の流れを説明する際に分析されます.
/* Read data. Try to read the first field of the header first to check the
* full length of the packet. When a whole packet is in memory this function
* will call the function to process the packet. And so forth. */
void clusterReadHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
char buf[sizeof(clusterMsg)];
ssize_t nread;
clusterMsg *hdr;
clusterLink *link = (clusterLink*) privdata;
int readlen, rcvbuflen;
REDIS_NOTUSED(el);
REDIS_NOTUSED(mask);
while(1) { /* Read as long as there is data to read. */
rcvbuflen = sdslen(link->rcvbuf);
if (rcvbuflen rcvbuf;
if (rcvbuflen == 8) {
/* Perform some sanity check on the message signature
* and length. */
if (memcmp(hdr->sig,"RCmb",4) != 0 ||
ntohl(hdr->totlen) totlen) - rcvbuflen;
if (readlen > sizeof(buf)) readlen = sizeof(buf);
}
// readlen
// fd , EAGAIN
nread = read(fd,buf,readlen);
if (nread == -1 && errno == EAGAIN) return; /* No more data ready. */
if (nread <= 0) {
/* I/O error... */
redisLog(REDIS_DEBUG,"I/O error reading from node link: %s",
(nread == 0) ? "connection closed" : strerror(errno));
handleLinkIOError(link);
return;
} else {
/* Read data and recast the pointer to the new buffer. */
link->rcvbuf = sdscatlen(link->rcvbuf,buf,nread);
hdr = (clusterMsg*) link->rcvbuf;
rcvbuflen += nread;
}
/* Total length obtained? Process this packet. */
if (rcvbuflen >= 8 && rcvbuflen == ntohl(hdr->totlen)) {
// link rcvbuf cluster
//
if (clusterProcessPacket(link)) {
sdsfree(link->rcvbuf);
link->rcvbuf = sdsempty();
} else {
return; /* Link no longer valid. */
}
}
}
}