void execCommand(redisClient *c) { int j; robj **orig_argv; int orig_argc; struct redisCommand *orig_cmd; if (!(c->flags & REDIS_MULTI)) { addReplyError(c,"EXEC without MULTI"); return; } /* Check if we need to abort the EXEC if some WATCHed key was touched. * A failed EXEC will return a multi bulk nil object. */ if (c->flags & REDIS_DIRTY_CAS) { freeClientMultiState(c); initClientMultiState(c); c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS); unwatchAllKeys(c); addReply(c,shared.nullmultibulk); return; } /* Replicate a MULTI request now that we are sure the block is executed. * This way we'll deliver the MULTI/..../EXEC block as a whole and * both the AOF and the replication link will have the same consistency * and atomicity guarantees. */ execCommandReplicateMulti(c); /* Exec all the queued commands */ unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */ orig_argv = c->argv; orig_argc = c->argc; orig_cmd = c->cmd; addReplyMultiBulkLen(c,c->mstate.count); for (j = 0; j < c->mstate.count; j++) { c->argc = c->mstate.commands[j].argc; c->argv = c->mstate.commands[j].argv; c->cmd = c->mstate.commands[j].cmd; call(c); /* Commands may alter argc/argv, restore mstate. */ c->mstate.commands[j].argc = c->argc; c->mstate.commands[j].argv = c->argv; c->mstate.commands[j].cmd = c->cmd; } c->argv = orig_argv; c->argc = orig_argc; c->cmd = orig_cmd; freeClientMultiState(c); initClientMultiState(c); c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS); /* Make sure the EXEC command is always replicated / AOF, since we * always send the MULTI command (we can't know beforehand if the * next operations will contain at least a modification to the DB). */ server.dirty++; }
void freeFakeClient(struct redisClient *c) { sdsfree(c->querybuf); listRelease(c->reply); listRelease(c->watched_keys); freeClientMultiState(c); zfree(c); }
void discardTransaction(client *c) { /* 释放动态内存 */ freeClientMultiState(c); /* 重新初始化 事务状态 */ initClientMultiState(c); /* 去除事务标识 */ c->flags &= ~(CLIENT_MULTI|CLIENT_DIRTY_CAS|CLIENT_DIRTY_EXEC); /* 释放所有WATCH的键 */ unwatchAllKeys(c); }
// 取消事务状态 void discardTransaction(client *c) { // 释放客户端的事务状态的所有资源 freeClientMultiState(c); // 初始化client的事务状态 initClientMultiState(c); // 取消客户端的事务有关的状态标识 c->flags &= ~(CLIENT_MULTI|CLIENT_DIRTY_CAS|CLIENT_DIRTY_EXEC); // 取消对客户端的所有的键的监视 unwatchAllKeys(c); }
// 取消事务 void discardTransaction(redisClient *c) { // 清空命令队列 freeClientMultiState(c); // 初始化命令队列 initClientMultiState(c); // 取消标记 flag c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC);; unwatchAllKeys(c); }
/* * 放弃事务,清理并重置客户端的事务状态 * * T = O(N^2) */ void discardTransaction(redisClient *c) { // 释放参数空间 freeClientMultiState(c); // 重置事务状态 initClientMultiState(c); // 关闭相关的 flag c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC);; // 取消所有 key 的监视, O(N^2) unwatchAllKeys(c); }
void discardCommand(redisClient *c) { if (!(c->flags & REDIS_MULTI)) { addReplyError(c,"DISCARD without MULTI"); return; } freeClientMultiState(c); initClientMultiState(c); c->flags &= (~REDIS_MULTI); unwatchAllKeys(c); addReply(c,shared.ok); }
void discardTransaction(redisClient *c) { // 重置事务状态 freeClientMultiState(c); initClientMultiState(c); // 屏蔽事务状态 c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC);; // 取消对所有键的监视 unwatchAllKeys(c); }
void freeClient(redisClient *c) { listNode *ln; /* Note that if the client we are freeing is blocked into a blocking * call, we have to set querybuf to NULL *before* to call * unblockClientWaitingData() to avoid processInputBuffer() will get * called. Also it is important to remove the file events after * this, because this call adds the READABLE event. */ sdsfree(c->querybuf); c->querybuf = NULL; if (c->flags & REDIS_BLOCKED) unblockClientWaitingData(c); /* UNWATCH all the keys */ unwatchAllKeys(c); listRelease(c->watched_keys); /* Unsubscribe from all the pubsub channels */ pubsubUnsubscribeAllChannels(c,0); pubsubUnsubscribeAllPatterns(c,0); dictRelease(c->pubsub_channels); listRelease(c->pubsub_patterns); /* Obvious cleanup */ aeDeleteFileEvent(server.el,c->fd,AE_READABLE); aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); listRelease(c->reply); freeClientArgv(c); close(c->fd); /* Remove from the list of clients */ ln = listSearchKey(server.clients,c); redisAssert(ln != NULL); listDelNode(server.clients,ln); /* Remove from the list of clients waiting for swapped keys, or ready * to be restarted, but not yet woken up again. */ if (c->flags & REDIS_IO_WAIT) { redisAssert(server.vm_enabled); if (listLength(c->io_keys) == 0) { ln = listSearchKey(server.io_ready_clients,c); /* When this client is waiting to be woken up (REDIS_IO_WAIT), * it should be present in the list io_ready_clients */ redisAssert(ln != NULL); listDelNode(server.io_ready_clients,ln); } else { while (listLength(c->io_keys)) { ln = listFirst(c->io_keys); dontWaitForSwappedKey(c,ln->value); } } server.vm_blocked_clients--; } listRelease(c->io_keys); /* Master/slave cleanup. * Case 1: we lost the connection with a slave. */ if (c->flags & REDIS_SLAVE) { if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1) close(c->repldbfd); list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves; ln = listSearchKey(l,c); redisAssert(ln != NULL); listDelNode(l,ln); } /* Case 2: we lost the connection with the master. */ if (c->flags & REDIS_MASTER) { server.master = NULL; server.replstate = REDIS_REPL_CONNECT; /* Since we lost the connection with the master, we should also * close the connection with all our slaves if we have any, so * when we'll resync with the master the other slaves will sync again * with us as well. Note that also when the slave is not connected * to the master it will keep refusing connections by other slaves. */ while (listLength(server.slaves)) { ln = listFirst(server.slaves); freeClient((redisClient*)ln->value); } } /* Release memory */ zfree(c->argv); zfree(c->mbargv); freeClientMultiState(c); zfree(c); }
// 放弃执行事务 void discardTransaction(redisClient *c) { freeClientMultiState(c); // 释放事务资源 initClientMultiState(c); // 重置事务状态 c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS);; // 关闭 FLAG unwatchAllKeys(c); // 取消对所有 key 的 WATCH }
// 执行事务 void execCommand(redisClient *c) { int j; robj **orig_argv; int orig_argc; struct redisCommand *orig_cmd; // 如果没执行过 MULTI ,报错 if (!(c->flags & REDIS_MULTI)) { addReplyError(c,"EXEC without MULTI"); return; } /* Check if we need to abort the EXEC if some WATCHed key was touched. * A failed EXEC will return a multi bulk nil object. */ // 如果在执行事务之前,有监视中(WATCHED)的 key 被改变 // 那么取消这个事务 if (c->flags & REDIS_DIRTY_CAS) { freeClientMultiState(c); initClientMultiState(c); c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS); unwatchAllKeys(c); addReply(c,shared.nullmultibulk); return; } /* Replicate a MULTI request now that we are sure the block is executed. * This way we'll deliver the MULTI/..../EXEC block as a whole and * both the AOF and the replication link will have the same consistency * and atomicity guarantees. */ // 为保证一致性和原子性 // 如果处在 AOF 模式中,向 AOF 文件发送 MULTI // 如果处在复制模式中,向附属节点发送 MULTI execCommandReplicateMulti(c); /* Exec all the queued commands */ // 开始执行所有事务中的命令(FIFO 方式) unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */ // 备份所有参数和命令 orig_argv = c->argv; orig_argc = c->argc; orig_cmd = c->cmd; addReplyMultiBulkLen(c,c->mstate.count); for (j = 0; j < c->mstate.count; j++) { c->argc = c->mstate.commands[j].argc; // 取出参数数量 c->argv = c->mstate.commands[j].argv; // 取出参数 c->cmd = c->mstate.commands[j].cmd; // 取出要执行的命令 call(c,REDIS_CALL_FULL); // 执行命令 /* Commands may alter argc/argv, restore mstate. */ c->mstate.commands[j].argc = c->argc; c->mstate.commands[j].argv = c->argv; c->mstate.commands[j].cmd = c->cmd; } // 恢复所有参数和命令 c->argv = orig_argv; c->argc = orig_argc; c->cmd = orig_cmd; // 重置事务状态 freeClientMultiState(c); initClientMultiState(c); c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS); /* Make sure the EXEC command is always replicated / AOF, since we * always send the MULTI command (we can't know beforehand if the * next operations will contain at least a modification to the DB). */ // 更新状态值,确保事务执行之后的状态为脏 server.dirty++; }
void discardTransaction(redisClient *c) { freeClientMultiState(c); initClientMultiState(c); c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC);; unwatchAllKeys(c); }
void execCommand(redisClient *c) { int j; robj **orig_argv; int orig_argc; struct redisCommand *orig_cmd; if (!(c->flags & REDIS_MULTI)) { addReplyError(c,"EXEC without MULTI"); return; } /* Check if we need to abort the EXEC if some WATCHed key was touched. * A failed EXEC will return a multi bulk nil object. */ if (c->flags & REDIS_DIRTY_CAS) { freeClientMultiState(c); initClientMultiState(c); c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS); unwatchAllKeys(c); addReply(c,shared.nullmultibulk); goto handle_monitor; } /* Replicate a MULTI request now that we are sure the block is executed. * This way we'll deliver the MULTI/..../EXEC block as a whole and * both the AOF and the replication link will have the same consistency * and atomicity guarantees. */ execCommandReplicateMulti(c); /* Exec all the queued commands */ unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */ orig_argv = c->argv; orig_argc = c->argc; orig_cmd = c->cmd; addReplyMultiBulkLen(c,c->mstate.count); for (j = 0; j < c->mstate.count; j++) { c->argc = c->mstate.commands[j].argc; c->argv = c->mstate.commands[j].argv; c->cmd = c->mstate.commands[j].cmd; call(c,REDIS_CALL_FULL); /* Commands may alter argc/argv, restore mstate. */ c->mstate.commands[j].argc = c->argc; c->mstate.commands[j].argv = c->argv; c->mstate.commands[j].cmd = c->cmd; } c->argv = orig_argv; c->argc = orig_argc; c->cmd = orig_cmd; freeClientMultiState(c); initClientMultiState(c); c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS); /* Make sure the EXEC command is always replicated / AOF, since we * always send the MULTI command (we can't know beforehand if the * next operations will contain at least a modification to the DB). */ server.dirty++; handle_monitor: /* Send EXEC to clients waiting data from MONITOR. We do it here * since the natural order of commands execution is actually: * MUTLI, EXEC, ... commands inside transaction ... * Instead EXEC is flagged as REDIS_CMD_SKIP_MONITOR in the command * table, and we do it here with correct ordering. */ if (listLength(server.monitors) && !server.loading) replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); }
void freeClient(redisClient *c) { listNode *ln; /* Note that if the client we are freeing is blocked into a blocking * call, we have to set querybuf to NULL *before* to call * unblockClientWaitingData() to avoid processInputBuffer() will get * called. Also it is important to remove the file events after * this, because this call adds the READABLE event. */ sdsfree(c->querybuf); c->querybuf = NULL; if (c->flags & REDIS_BLOCKED) unblockClientWaitingData(c); /* UNWATCH all the keys */ unwatchAllKeys(c); listRelease(c->watched_keys); /* Unsubscribe from all the pubsub channels */ pubsubUnsubscribeAllChannels(c,0); pubsubUnsubscribeAllPatterns(c,0); dictRelease(c->pubsub_channels); listRelease(c->pubsub_patterns); /* Obvious cleanup */ aeDeleteFileEvent(server.el,c->fd,AE_READABLE); aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); listRelease(c->reply); freeClientArgv(c); close(c->fd); /* Remove from the list of clients */ ln = listSearchKey(server.clients,c); redisAssert(ln != NULL); listDelNode(server.clients,ln); /* Remove from the list of clients that are now ready to be restarted * after waiting for swapped keys */ if (c->flags & REDIS_IO_WAIT && listLength(c->io_keys) == 0) { ln = listSearchKey(server.io_ready_clients,c); if (ln) { listDelNode(server.io_ready_clients,ln); server.vm_blocked_clients--; } } /* Remove from the list of clients waiting for swapped keys */ while (server.vm_enabled && listLength(c->io_keys)) { ln = listFirst(c->io_keys); dontWaitForSwappedKey(c,ln->value); } listRelease(c->io_keys); /* Master/slave cleanup */ if (c->flags & REDIS_SLAVE) { if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1) close(c->repldbfd); list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves; ln = listSearchKey(l,c); redisAssert(ln != NULL); listDelNode(l,ln); } if (c->flags & REDIS_MASTER) { server.master = NULL; server.replstate = REDIS_REPL_CONNECT; } /* Release memory */ zfree(c->argv); zfree(c->mbargv); freeClientMultiState(c); zfree(c); }
/* * EXEC 命令的实现 */ void execCommand(redisClient *c) { int j; // 用于保存执行命令、命令的参数和参数数量的副本 robj **orig_argv; int orig_argc; struct redisCommand *orig_cmd; // 只能在 MULTI 已启用的情况下执行 if (!(c->flags & REDIS_MULTI)) { addReplyError(c,"EXEC without MULTI"); return; } /* Check if we need to abort the EXEC because: * 以下情况发生时,取消事务 * * 1) Some WATCHed key was touched. * 某些被监视的键已被修改(状态为 REDIS_DIRTY_CAS) * * 2) There was a previous error while queueing commands. * 有命令在入队时发生错误(状态为 REDIS_DIRTY_EXEC) * * A failed EXEC in the first case returns a multi bulk nil object * (technically it is not an error but a special behavior), while * in the second an EXECABORT error is returned. * * 第一种情况返回多个空白 NULL 对象, * 第二种情况返回一个 EXECABORT 错误。 */ if (c->flags & (REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC)) { // 根据状态,决定返回的错误的类型 addReply(c, c->flags & REDIS_DIRTY_EXEC ? shared.execaborterr : shared.nullmultibulk); // 以下四句可以用 discardTransaction() 来替换 freeClientMultiState(c); initClientMultiState(c); c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC); unwatchAllKeys(c); goto handle_monitor; } /* Replicate a MULTI request now that we are sure the block is executed. * This way we'll deliver the MULTI/..../EXEC block as a whole and * both the AOF and the replication link will have the same consistency * and atomicity guarantees. */ // 向所有附属节点和 AOF 文件发送 MULTI 命令 execCommandReplicateMulti(c); /* Exec all the queued commands */ unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */ // 将三个原始参数备份起来 orig_argv = c->argv; orig_argc = c->argc; orig_cmd = c->cmd; addReplyMultiBulkLen(c,c->mstate.count); // 执行所有入队的命令 for (j = 0; j < c->mstate.count; j++) { // 因为 call 可能修改命令,而命令需要传送给其他同步节点 // 所以这里将要执行的命令(及其参数)先备份起来 c->argc = c->mstate.commands[j].argc; c->argv = c->mstate.commands[j].argv; c->cmd = c->mstate.commands[j].cmd; // 执行命令 call(c,REDIS_CALL_FULL); /* Commands may alter argc/argv, restore mstate. */ // 还原原始的参数到队列里 c->mstate.commands[j].argc = c->argc; c->mstate.commands[j].argv = c->argv; c->mstate.commands[j].cmd = c->cmd; } // 还原三个原始命令 c->argv = orig_argv; c->argc = orig_argc; c->cmd = orig_cmd; // 以下三句也可以用 discardTransaction() 来替换 freeClientMultiState(c); initClientMultiState(c); c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC); /* Make sure the EXEC command is always replicated / AOF, since we * always send the MULTI command (we can't know beforehand if the * next operations will contain at least a modification to the DB). */ server.dirty++; handle_monitor: /* Send EXEC to clients waiting data from MONITOR. We do it here * since the natural order of commands execution is actually: * MUTLI, EXEC, ... commands inside transaction ... * Instead EXEC is flagged as REDIS_CMD_SKIP_MONITOR in the command * table, and we do it here with correct ordering. */ // 向同步节点发送命令 if (listLength(server.monitors) && !server.loading) replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); }