void Master::MessageReceived(ChannelHandlerContext& ctx, MessageEvent<RedisCommandFrame>& e) { RedisCommandFrame* cmd = e.GetMessage(); DEBUG_LOG("Master recv cmd from slave:%s", cmd->ToString().c_str()); if (!strcasecmp(cmd->GetCommand().c_str(), "replconf")) { if (cmd->GetArguments().size() == 2 && !strcasecmp(cmd->GetArguments()[0].c_str(), "ack")) { int64 offset; if (string_toint64(cmd->GetArguments()[1], offset)) { SlaveConnTable::iterator found = m_slaves.find(ctx.GetChannel()->GetID()); if (found != m_slaves.end()) { SlaveConn* slave = found->second; if (NULL != slave) { slave->acktime = time(NULL); slave->ack_offset = offset; } } } } } }
bool conf_get_int64(const Properties& conf, const std::string& name, int64& value, bool ignore_nonexist) { Properties::const_iterator found = conf.find(name); if (found == conf.end()) { return ignore_nonexist; } if (string_toint64(found->second, value)) { return true; } std::string size_str = string_toupper(found->second); value = atoll(size_str.c_str()); if (size_str.find("M") == (size_str.size() - 1) || size_str.find("MB") == (size_str.size() - 2)) { value *= (1024 * 1024); // convert to megabytes } else if (size_str.find("G") == (size_str.size() - 1) || size_str.find("GB") == (size_str.size() - 2)) { value *= (1024 * 1024 * 1024); // convert to kilobytes } else if (size_str.find("K") == (size_str.size() - 1) || size_str.find("KB") == (size_str.size() - 2)) { value *= 1024; // convert to kilobytes } else { return false; } return true; }
void Master::AddSlave(Channel* slave, RedisCommandFrame& cmd) { DEBUG_LOG("Recv sync command:%s", cmd.ToString().c_str()); slave->Flush(); SlaveConnection* conn = NULL; NEW(conn, SlaveConnection); conn->conn = slave; if (!strcasecmp(cmd.GetCommand().c_str(), "sync")) { //Redis 2.6/2.4 send 'sync' conn->isRedisSlave = true; conn->sync_offset = -1; } else { conn->server_key = cmd.GetArguments()[0]; const std::string& offset_str = cmd.GetArguments()[1]; if (!string_toint64(offset_str, conn->sync_offset)) { ERROR_LOG("Invalid offset argument:%s", offset_str.c_str()); slave->Close(); DELETE(conn); return; } //Redis 2.8+ send psync, Ardb send psync2 if (!strcasecmp(cmd.GetCommand().c_str(), "psync")) { conn->isRedisSlave = true; } else { conn->isRedisSlave = false; if (cmd.GetArguments().size() >= 3) { std::vector<std::string> ss = split_string(cmd.GetArguments()[2], "|"); for (uint32 i = 0; i < ss.size(); i++) { DBID id; if (string_touint32(ss[i], id)) { conn->syncdbs.insert(id); } } } } } m_server->m_service->DetachChannel(slave, true); ReplicationInstruction inst(conn, REPL_INSTRUCTION_ADD_SLAVE); OfferReplInstruction(inst); }
void Master::AddSlave(Channel* slave, RedisCommandFrame& cmd) { INFO_LOG("[Master]Recv sync command:%s", cmd.ToString().c_str()); slave->Flush(); SlaveConn& conn = GetSlaveConn(slave); if (!strcasecmp(cmd.GetCommand().c_str(), "sync")) { //Redis 2.6/2.4 send 'sync' conn.isRedisSlave = true; conn.sync_offset = -1; } else { conn.server_key = cmd.GetArguments()[0]; const std::string& offset_str = cmd.GetArguments()[1]; if (!string_toint64(offset_str, conn.sync_offset)) { ERROR_LOG("Invalid offset argument:%s", offset_str.c_str()); slave->Close(); return; } conn.isRedisSlave = true; for (uint32 i = 2; i < cmd.GetArguments().size(); i += 2) { if (cmd.GetArguments()[i] == "cksm") { conn.isRedisSlave = false; if (!string_touint64(cmd.GetArguments()[i + 1], conn.sync_cksm)) { ERROR_LOG("Invalid checksum argument:%s", cmd.GetArguments()[i + 1].c_str()); slave->Close(); return; } } } } slave->GetService().DetachChannel(slave, true); if (g_repl->GetIOServ().IsInLoopThread()) { AddSlave(&conn); } else { g_repl->GetIOServ().AsyncIO(0, OnAddSlave, &conn); } }
int ArdbServer::Decrby(ArdbConnContext& ctx, RedisCommandFrame& cmd) { int64 decrement, val; if (!string_toint64(cmd.GetArguments()[1], decrement)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } int ret = m_db->Decrby(ctx.currentDB, cmd.GetArguments()[0], decrement, val); if (ret == 0) { fill_int_reply(ctx.reply, val); } else { fill_error_reply(ctx.reply, "value is not an integer or out of range"); } return 0; }
void Slave::HandleRedisReply(Channel* ch, RedisReply& reply) { switch (m_slave_state) { case SLAVE_STATE_WAITING_INFO_REPLY: { if (reply.type == REDIS_REPLY_ERROR) { ERROR_LOG("Recv info reply error:%s", reply.str.c_str()); Close(); return; } const char* redis_ver_key = "redis_version:"; if (reply.str.find(redis_ver_key) != std::string::npos) { m_server_type = REDIS_DB_SERVER_TYPE; size_t start = reply.str.find(redis_ver_key); size_t end = reply.str.find("\n", start); std::string v = reply.str.substr(start + strlen(redis_ver_key), end - start - strlen(redis_ver_key)); v = trim_string(v); m_server_support_psync = (compare_version<3>(v, "2.7.0") >= 0); INFO_LOG("[Slave]Remote master is a Redis %s instance, support partial sync:%u", v.c_str(), m_server_support_psync); } else { INFO_LOG("[Slave]Remote master is an Ardb instance."); m_server_type = ARDB_DB_SERVER_TYPE; m_server_support_psync = true; } Buffer replconf; replconf.Printf("replconf listening-port %u\r\n", m_serv->GetServerConfig().listen_port); ch->Write(replconf); m_slave_state = SLAVE_STATE_WAITING_REPLCONF_REPLY; break; } case SLAVE_STATE_WAITING_REPLCONF_REPLY: { if (reply.type == REDIS_REPLY_ERROR) { ERROR_LOG("Recv replconf reply error:%s", reply.str.c_str()); ch->Close(); return; } if (m_server_support_psync) { Buffer sync; if (m_server_type == ARDB_DB_SERVER_TYPE) { std::string includes = "*"; std::string excludes = "-"; if (!m_include_dbs.empty()) { includes = string_join_container(m_include_dbs, "|"); } if (!m_exclude_dbs.empty()) { excludes = string_join_container(m_exclude_dbs, "|"); } sync.Printf("apsync %s %lld cksm %llu include %s exclude %s\r\n", m_backlog.GetServerKey(), m_backlog.GetReplEndOffset(), m_backlog.GetChecksum(), includes.c_str(), excludes.c_str()); } else { sync.Printf("psync %s %lld\r\n", m_backlog.GetServerKey(), m_backlog.GetReplEndOffset()); INFO_LOG("Send PSYNC %s %lld", m_backlog.GetServerKey(), m_backlog.GetReplEndOffset()); } ch->Write(sync); m_slave_state = SLAVE_STATE_WAITING_PSYNC_REPLY; } else { Buffer sync; sync.Printf("sync\r\n"); ch->Write(sync); m_slave_state = SLAVE_STATE_SYNING_DUMP_DATA; m_decoder.SwitchToDumpFileDecoder(); } break; } case SLAVE_STATE_WAITING_PSYNC_REPLY: { if (reply.type != REDIS_REPLY_STATUS) { ERROR_LOG("Recv psync reply error:%s", reply.str.c_str()); ch->Close(); return; } INFO_LOG("Recv psync reply:%s", reply.str.c_str()); std::vector<std::string> ss = split_string(reply.str, " "); if (!strcasecmp(ss[0].c_str(), "FULLRESYNC")) { int64 offset; if (!string_toint64(ss[2], offset)) { ERROR_LOG("Invalid psync offset:%s", ss[2].c_str()); ch->Close(); return; } /* * Delete all data before receiving resyncing data */ if (m_serv->m_cfg.slave_cleardb_before_fullresync) { m_serv->m_db->FlushAll(); } m_backlog.SetServerkey(ss[1]); m_backlog.SetReplOffset(offset); if (m_server_type == ARDB_DB_SERVER_TYPE) { //Do NOT change state, since master would send "FULLSYNCED" after all data synced m_decoder.SwitchToCommandDecoder(); return; } } else if (!strcasecmp(ss[0].c_str(), "CONTINUE")) { m_decoder.SwitchToCommandDecoder(); m_slave_state = SLAVE_STATE_SYNCED; break; } else { ERROR_LOG("Invalid psync status:%s", reply.str.c_str()); ch->Close(); return; } m_slave_state = SLAVE_STATE_SYNING_DUMP_DATA; m_decoder.SwitchToDumpFileDecoder(); break; } default: { ERROR_LOG("Slave client is in invalid state:%d", m_slave_state); Close(); break; } } }