int master_init(vr_conf *conf) { rstatus_t status; uint32_t j; sds *host, listen_str; vr_listen **vlisten; int threads_num; int filelimit; master.cbsul = NULL; pthread_mutex_init(&master.cbsullock, NULL); conf_server_get(CONFIG_SOPN_THREADS,&threads_num); filelimit = threads_num*2+CONFIG_MIN_RESERVED_FDS; vr_eventloop_init(&master.vel,filelimit); master.vel.thread.fun_run = master_thread_run; darray_init(&master.listens,darray_n(&cserver->binds),sizeof(vr_listen*)); for (j = 0; j < darray_n(&cserver->binds); j ++) { host = darray_get(&cserver->binds,j); listen_str = sdsdup(*host); listen_str = sdscatfmt(listen_str, ":%i", cserver->port); vlisten = darray_push(&master.listens); *vlisten = vr_listen_create(listen_str); if (*vlisten == NULL) { darray_pop(&master.listens); log_error("Create listen %s failed", listen_str); sdsfree(listen_str); return VR_ERROR; } sdsfree(listen_str); } for (j = 0; j < darray_n(&master.listens); j ++) { vlisten = darray_get(&master.listens, j); status = vr_listen_begin(*vlisten); if (status != VR_OK) { log_error("Begin listen to %s failed", (*vlisten)->name); return VR_ERROR; } } master.cbsul = dlistCreate(); if (master.cbsul == NULL) { log_error("Create list failed: out of memory"); return VR_ENOMEM; } setup_master(); return VR_OK; }
/* If this function gets called we already read a whole * command, arguments are in the client argv/argc fields. * processCommand() execute the command or prepare the * server for a bulk read from the client. * * If VR_OK is returned the client is still alive and valid and * other operations can be performed by the caller. Otherwise * if VR_ERROR is returned the client was destroyed (i.e. after QUIT). */ int processCommand(client *c) { long long maxmemory; /* The QUIT command is handled separately. Normal command procs will * go through checking for replication and QUIT will cause trouble * when FORCE_REPLICATION is enabled and would be implemented in * a regular command proc. */ if (!strcasecmp(c->argv[0]->ptr,"quit")) { addReply(c,shared.ok); c->flags |= CLIENT_CLOSE_AFTER_REPLY; return VR_ERROR; } /* Now lookup the command and check ASAP about trivial error conditions * such as wrong arity, bad command name and so forth. */ c->cmd = c->lastcmd = lookupCommand(c->argv[0]->ptr); if (!c->cmd) { flagTransaction(c); addReplyErrorFormat(c,"unknown command '%s'", (char*)c->argv[0]->ptr); return VR_OK; } else if ((c->cmd->arity > 0 && c->cmd->arity != c->argc) || (c->argc < -c->cmd->arity)) { flagTransaction(c); addReplyErrorFormat(c,"wrong number of arguments for '%s' command", c->cmd->name); return VR_OK; } /* Check if the user is authenticated */ if (server.requirepass && !c->authenticated && c->cmd->proc != authCommand) { flagTransaction(c); addReply(c,shared.noautherr); return VR_OK; } /* Handle the maxmemory directive. * * First we try to free some memory if possible (if there are volatile * keys in the dataset). If there are not the only thing we can do * is returning an error. */ conf_server_get(CONFIG_SOPN_MAXMEMORY,&maxmemory); if (maxmemory) { int retval = freeMemoryIfNeeded(c->vel); /* freeMemoryIfNeeded may flush slave output buffers. This may result * into a slave, that may be the active client, to be freed. */ if (c->vel->current_client == NULL) return VR_ERROR; /* It was impossible to free enough memory, and the command the client * is trying to execute is denied during OOM conditions? Error. */ if ((c->cmd->flags & CMD_DENYOOM) && retval == VR_ERROR) { flagTransaction(c); addReply(c, shared.oomerr); return VR_OK; } } /* Don't accept write commands if there are problems persisting on disk * and if this is a master instance. */ if (((server.stop_writes_on_bgsave_err && server.saveparamslen > 0 && server.lastbgsave_status == VR_ERROR) || server.aof_last_write_status == VR_ERROR) && repl.masterhost == NULL && (c->cmd->flags & CMD_WRITE || c->cmd->proc == pingCommand)) { flagTransaction(c); if (server.aof_last_write_status == VR_OK) addReply(c, shared.bgsaveerr); else addReplySds(c, sdscatprintf(sdsempty(), "-MISCONF Errors writing to the AOF file: %s\r\n", strerror(server.aof_last_write_errno))); return VR_OK; } /* Don't accept write commands if there are not enough good slaves and * user configured the min-slaves-to-write option. */ if (repl.masterhost == NULL && repl.repl_min_slaves_to_write && repl.repl_min_slaves_max_lag && c->cmd->flags & CMD_WRITE && repl.repl_good_slaves_count < repl.repl_min_slaves_to_write) { flagTransaction(c); addReply(c, shared.noreplicaserr); return VR_OK; } /* Don't accept write commands if this is a read only slave. But * accept write commands if this is our master. */ if (repl.masterhost && repl.repl_slave_ro && !(c->flags & CLIENT_MASTER) && c->cmd->flags & CMD_WRITE) { addReply(c, shared.roslaveerr); return VR_OK; } /* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */ if (c->flags & CLIENT_PUBSUB && c->cmd->proc != pingCommand && c->cmd->proc != subscribeCommand && c->cmd->proc != unsubscribeCommand && c->cmd->proc != psubscribeCommand && c->cmd->proc != punsubscribeCommand) { addReplyError(c,"only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this context"); return VR_OK; } /* Only allow INFO and SLAVEOF when slave-serve-stale-data is no and * we are a slave with a broken link with master. */ if (repl.masterhost && repl.repl_state != REPL_STATE_CONNECTED && repl.repl_serve_stale_data == 0 && !(c->cmd->flags & CMD_STALE)) { flagTransaction(c); addReply(c, shared.masterdownerr); return VR_OK; } /* Loading DB? Return an error if the command has not the * CMD_LOADING flag. */ if (server.loading && !(c->cmd->flags & CMD_LOADING)) { addReply(c, shared.loadingerr); return VR_OK; } /* Lua script too slow? Only allow a limited number of commands. */ if (server.lua_timedout && c->cmd->proc != authCommand && c->cmd->proc != replconfCommand && !(c->cmd->proc == shutdownCommand && c->argc == 2 && tolower(((char*)c->argv[1]->ptr)[0]) == 'n') && !(c->cmd->proc == scriptCommand && c->argc == 2 && tolower(((char*)c->argv[1]->ptr)[0]) == 'k')) { flagTransaction(c); addReply(c, shared.slowscripterr); return VR_OK; } /* Exec the command */ if (c->flags & CLIENT_MULTI && c->cmd->proc != execCommand && c->cmd->proc != discardCommand && c->cmd->proc != multiCommand && c->cmd->proc != watchCommand) { queueMultiCommand(c); addReply(c,shared.queued); } else { call(c,CMD_CALL_FULL); c->woff = repl.master_repl_offset; if (listLength(server.ready_keys)) handleClientsBlockedOnLists(); } return VR_OK; }