typedef struct redisObject {
unsigned type:4; //0string 1list 2set 3zset 4hash
unsigned notused:2; /* Not used */
unsigned encoding:4; //0raw, 1int, 2hashtable 3zipmap ...
unsigned lru:22; /* lru time (relative to server.lruclock) */
int refcount; //记录有多少个指针指向该redisObject。为1时则释放(因为会decr一下),否则减1.
void *ptr; //sds类型, 即, char*类型。 ptr的前sizeof(struct sdshdr)是个结构体{len, free}表示该串的长度和可写内存长度
} robj; //redis中的key和value都是这种类型的指针。
typedef struct redisDb {
dict *dict; /* The keyspace for this DB */
dict *expires; /* Timeout of keys with a timeout set */
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) */
dict *ready_keys; /* Blocked keys that received a PUSH */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */ 维护的<key, list>, list中表示watch了该key 的redisClient
int id;
long long avg_ttl; /* Average TTL, just for stats */
} redisDb;
/* With multiplexing we need to take per-client state.
* Clients are taken in a liked list. */
typedef struct redisClient {
int fd;
redisDb *db;
int dictid;
robj *name; /* As set by CLIENT SETNAME */
sds querybuf;
size_t querybuf_peak; /* Recent (100ms or more) peak of querybuf size */
int argc;
robj **argv;
struct redisCommand *cmd, *lastcmd;
int reqtype;
int multibulklen; /* number of multi bulk arguments left to read */
long bulklen; /* length of bulk argument in multi bulk request */
list *reply;
unsigned long reply_bytes; /* Tot bytes of objects in reply list */
int sentlen; /* Amount of bytes already sent in the current
buffer or object being sent. */
time_t ctime; /* Client creation time */
time_t lastinteraction; /* time of the last interaction, used for timeout */
time_t obuf_soft_limit_reached_time;
int flags; /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
int authenticated; /* when requirepass is non-NULL */
int replstate; /* replication state if this is a slave */
int repldbfd; /* replication DB file descriptor */
off_t repldboff; /* replication DB file offset */
off_t repldbsize; /* replication DB file size */
long long reploff; /* replication offset if this is our master */
long long repl_ack_off; /* replication ack offset, if this is a slave */
long long repl_ack_time;/* replication ack time, if this is a slave */
char replrunid[REDIS_RUN_ID_SIZE+1]; /* master run id if this is a master */
int slave_listening_port; /* As configured with: SLAVECONF listening-port */
multiState mstate; /* MULTI/EXEC state */client每次发一个命令过来。 如果client开始watch或者事物,则client的相关命令queueMultiCommand存到此处。
blockingState bpop; /* blocking state */
list *watched_keys; /* Keys WATCHED for MULTI/EXEC CAS */ 该clientwatch的key的列表。
dict *pubsub_channels; /* channels a client is interested in (SUBSCRIBE) */
list *pubsub_patterns; /* patterns a client is interested in (SUBSCRIBE) */
/* Response buffer */
int bufpos;
char buf[REDIS_REPLY_CHUNK_BYTES];
} redisClient;
/*
watch逻辑:先判断该client是否已watch过; 没有则在redisClient::watched_keys中增加、且在redisDB::watched_keys的该key列表下增加该redisClient
unwatch逻辑:上述逆过程
touchWatchedKey:遍历redisDB::watched_keys中该key的client列表, 将逐个client的flags |= REDIS_DIRTY_CAS。 client在exec时发现该标志则放弃事务。
在开启事务后, 该client后续的command都会被queue到redisClient::mstate中,
如果中途用户discard则unwatch所有、回复相关状态, 否则直到exec时:先判断是否watch的被其他改变,否则逐条执行此前缓存的command
当key被修改时, 如set/del/rename?等操作时, 会将redisDB::watched_keys中该key的所有redisClient的flag设为DIRTY_CAS; redisClient后续exec时会检查该标记。
*/
struct redisCommand {
char *name;
redisCommandProc *proc;
int arity;
char *sflags; /* Flags as string representation, one char per flag. */
int flags; /* The actual flags, obtained from the 'sflags' field. */
/* Use a function to determine keys arguments in a command line. */
redisGetKeysProc *getkeys_proc;
/* What keys should be loaded in background when calling this command? */
int firstkey; /* The first argument that's a key (0 = no keys) */
int lastkey; /* The last argument that's a key */
int keystep; /* The step between first and last key */
long long microseconds, calls;
};
/* Client MULTI/EXEC state */
typedef struct multiCmd {
robj **argv;
int argc;
struct redisCommand *cmd;
} multiCmd;
typedef struct multiState {
multiCmd *commands; /* Array of MULTI commands */
int count; /* Total number of MULTI commands */
int minreplicas; /* MINREPLICAS for synchronous replication */
time_t minreplicas_timeout; /* MINREPLICAS timeout as unixtime. */
} multiState;