int Ardb::BRPopLPush(Context& ctx, RedisCommandFrame& cmd) { uint32 timeout; if (!string_touint32(cmd.GetArguments()[cmd.GetArguments().size() - 1], timeout)) { fill_error_reply(ctx.reply, "timeout is not an integer or out of range"); return 0; } RPopLPush(ctx, cmd); if (ctx.reply.type == REDIS_REPLY_NIL) { //block; AddBlockKey(ctx, cmd.GetArguments()[0]); if (NULL != ctx.client) { ctx.client->DetachFD(); if (timeout > 0) { ctx.block->blocking_timer_task_id = ctx.client->GetService().GetTimer().ScheduleHeapTask( new BlockConnectionTimeout(&ctx), timeout, -1, SECONDS); } } ctx.reply.type = 0; } return 0; }
int Comms::RPopLPush(Context& ctx, RedisCommandFrame& cmd) { std::string v; int err = m_kv_store->RPopLPush(ctx.currentDB, cmd.GetArguments()[0], cmd.GetArguments()[1], v); if (err >= 0) { fill_str_reply(ctx.reply, v); FireKeyChangedEvent(ctx, cmd.GetArguments()[0]); FireKeyChangedEvent(ctx, cmd.GetArguments()[1]); if (cmd.GetType() == REDIS_CMD_BRPOPLPUSH) { ctx.current_cmd->SetCommand("rpoplpush"); } } else { if (err == mmkv::ERR_ENTRY_NOT_EXIST || err == mmkv::ERR_DB_NOT_EXIST) { ctx.reply.type = REDIS_REPLY_NIL; } else { FillErrorReply(ctx, err); } } return 0; }
int Comms::LInsert(Context& ctx, RedisCommandFrame& cmd) { bool before_or_after = false; if (!strcasecmp(cmd.GetArguments()[1].c_str(), "before")) { before_or_after = true; } else if (!strcasecmp(cmd.GetArguments()[1].c_str(), "after")) { before_or_after = false; } else { fill_error_reply(ctx.reply, "Syntax error"); return 0; } int err = m_kv_store->LInsert(ctx.currentDB, cmd.GetArguments()[0], before_or_after, cmd.GetArguments()[2], cmd.GetArguments()[3]); if (err >= 0 || -1 == err) { fill_int_reply(ctx.reply, err); if (err > 0) { FireKeyChangedEvent(ctx, cmd.GetArguments()[0]); } } else { FillErrorReply(ctx, err); } return 0; }
OP_NAMESPACE_BEGIN int Comms::LIndex(Context& ctx, RedisCommandFrame& cmd) { int64 index; if (!GetInt64Value(ctx, cmd.GetArguments()[1], index)) { return 0; } std::string v; int err = m_kv_store->LIndex(ctx.currentDB, cmd.GetArguments()[0], index, v); if (err >= 0) { fill_str_reply(ctx.reply, v); } else if (mmkv::ERR_OFFSET_OUTRANGE == err) { ctx.reply.type = REDIS_REPLY_NIL; } else { FillErrorReply(ctx, err); } return 0; }
int Ardb::HMGet(Context& ctx, RedisCommandFrame& cmd) { ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); ctx.reply.type = REDIS_REPLY_ARRAY; if (err == 0) { for (uint32 i = 1; i < cmd.GetArguments().size(); i++) { Data value; Data field(cmd.GetArguments()[i]); RedisReply& r = ctx.reply.AddMember(); if (0 == HashGet(ctx, meta, field, value)) { r.type = REDIS_REPLY_STRING; value.GetDecodeString(r.str); } else { r.type = REDIS_REPLY_NIL; } } } else { ctx.reply.ReserveMember(cmd.GetArguments().size()); } return 0; }
int Ardb::HMSet(Context& ctx, RedisCommandFrame& cmd) { if (m_cfg.replace_for_hmset) { HReplace(ctx, cmd); return 0; } if ((cmd.GetArguments().size() - 1) % 2 != 0) { fill_error_reply(ctx.reply, "wrong number of arguments for HMSet"); return 0; } ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); DataMap fs; for (uint32 i = 1; i < cmd.GetArguments().size(); i += 2) { Data f(cmd.GetArguments()[i]), v(cmd.GetArguments()[i + 1]); fs[f] = v; } HashMultiSet(ctx, meta, fs); fill_status_reply(ctx.reply, "OK"); return 0; }
int Ardb::HIncrbyFloat(Context& ctx, RedisCommandFrame& cmd) { double increment, val = 0; if (!GetDoubleValue(ctx, cmd.GetArguments()[2], increment)) { return 0; } ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); Data value; Data field(cmd.GetArguments()[1]); if (0 == err) { HashGet(ctx, meta, field, value); if (!value.GetDouble(val)) { fill_error_reply(ctx.reply, "value is not a float or out of range"); return 0; } } val += increment; std::string tmp; fast_dtoa(val, 10, tmp); value.SetString(tmp, false); HashSet(ctx, meta, field, value); fill_str_reply(ctx.reply, tmp); return 0; }
int Ardb::HIncrby(Context& ctx, RedisCommandFrame& cmd) { int64 increment, val = 0; if (!GetInt64Value(ctx, cmd.GetArguments()[2], increment)) { return 0; } ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); Data field(cmd.GetArguments()[1]); Data value; if (err == 0) { err = HashGet(ctx, meta, field, value); } if (err == ERR_NOT_EXIST) { value.SetInt64(increment); } else { if (!value.GetInt64(val)) { fill_error_reply(ctx.reply, "value is not a integer or out of range"); return 0; } value.SetInt64(val + increment); } HashSet(ctx, meta, field, value); fill_int_reply(ctx.reply, val + increment); return 0; }
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; } } } } } }
int Comms::Del(Context& ctx, RedisCommandFrame& cmd) { mmkv::DataArray fs; for (uint32 i = 0; i < cmd.GetArguments().size(); i++) { fs.push_back(cmd.GetArguments()[i]); } int err = m_kv_store->Del(ctx.currentDB, fs); if (err >= 0) { if (err > 0) { for (uint32 i = 0; i < cmd.GetArguments().size(); i++) { FireKeyChangedEvent(ctx, cmd.GetArguments()[i]); } } fill_int_reply(ctx.reply, err); } else { FillErrorReply(ctx, err); } return 0; }
/* * GEOADD key MERCATOR|WGS84 x y value [x y value....] */ int Ardb::GeoAdd(Context& ctx, RedisCommandFrame& cmd) { GeoAddOptions options; std::string err; if (0 != options.Parse(cmd.GetArguments(), err, 1)) { fill_error_reply(ctx.reply, "%s", err.c_str()); return 0; } GeoHashRange lat_range, lon_range; GeoHashHelper::GetCoordRange(options.coord_type, lat_range, lon_range); KeyLockerGuard keylock(m_key_lock, ctx.currentDB, cmd.GetArguments()[0]); ValueObject meta; int ret = GetMetaValue(ctx, cmd.GetArguments()[0], ZSET_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, ret); RedisCommandFrame zadd("zadd"); zadd.AddArg(cmd.GetArguments()[0]); BatchWriteGuard guard(GetKeyValueEngine()); GeoPointArray::iterator git = options.points.begin(); uint32 count = 0; while (git != options.points.end()) { GeoPoint& point = *git; if (point.x < lon_range.min || point.x > lon_range.max || point.y < lat_range.min || point.y > lat_range.max) { guard.MarkFailed(); break; } GeoHashBits hash; geohash_encode(&lat_range, &lon_range, point.y, point.x, 30, &hash); GeoHashFix60Bits score = hash.bits; Data score_value; score_value.SetInt64((int64) score); Data element; element.SetString(point.value, true); count += ZSetAdd(ctx, meta, element, score_value, NULL); std::string tmp; score_value.GetDecodeString(tmp); zadd.AddArg(tmp); element.GetDecodeString(tmp); zadd.AddArg(tmp); git++; } if (guard.Success()) { SetKeyValue(ctx, meta); RewriteClientCommand(ctx, zadd); fill_int_reply(ctx.reply, count); } else { fill_error_reply(ctx.reply, "Invalid arguments"); } return 0; }
void Slave::HandleRedisCommand(Channel* ch, RedisCommandFrame& cmd) { int flag = ARDB_PROCESS_REPL_WRITE; if (m_slave_state == SLAVE_STATE_SYNCED || m_slave_state == SLAVE_STATE_LOADING_DUMP_DATA) { flag |= ARDB_PROCESS_FORCE_REPLICATION; } else { flag |= ARDB_PROCESS_WITHOUT_REPLICATION; } DEBUG_LOG("Recv master cmd %s at %lld at flag:%d at state:%d", cmd.ToString().c_str(), m_backlog.GetReplEndOffset(), flag, m_slave_state); if (m_slave_state == SLAVE_STATE_WAITING_PSYNC_REPLY && m_server_type == ARDB_DB_SERVER_TYPE) { if (!strcasecmp(cmd.GetCommand().c_str(), "FULLSYNCED")) { uint64 offset, cksm; string_touint64(cmd.GetArguments()[0], offset); string_touint64(cmd.GetArguments()[1], cksm); m_backlog.SetChecksum(cksm); ASSERT(offset == m_backlog.GetReplEndOffset()); //m_backlog.SetReplOffset(offset); m_slave_state = SLAVE_STATE_SYNCED; //Disconnect all slaves when all data resynced m_serv->m_master_serv.DisconnectAllSlaves(); return; } } if (!strcasecmp(cmd.GetCommand().c_str(), "PING")) { m_ping_recved_time = time(NULL); } else if (!strcasecmp(cmd.GetCommand().c_str(), "SELECT")) { DBID id = 0; string_touint32(cmd.GetArguments()[0], id); m_backlog.SetCurrentDBID(id); } GetArdbConnContext(); m_actx->is_slave_conn = true; m_actx->conn = ch; if (strcasecmp(cmd.GetCommand().c_str(), "SELECT") && strcasecmp(cmd.GetCommand().c_str(), "__SET__") && strcasecmp(cmd.GetCommand().c_str(), "__DEL__")) { if (!m_include_dbs.empty() && m_include_dbs.count(m_actx->currentDB) == 0) { flag |= ARDB_PROCESS_FEED_REPLICATION_ONLY; } if (!m_exclude_dbs.empty() && m_exclude_dbs.count(m_actx->currentDB) > 0) { flag |= ARDB_PROCESS_FEED_REPLICATION_ONLY; } } m_serv->ProcessRedisCommand(*m_actx, cmd, flag); }
int Ardb::PSubscribe(Context& ctx, RedisCommandFrame& cmd) { ctx.client->GetWritableOptions().max_write_buffer_size = (int32)(m_cfg.pubsub_client_output_buffer_limit); for (uint32 i = 0; i < cmd.GetArguments().size(); i++) { PSubscribeChannel(ctx, cmd.GetArguments()[i], true); } return 0; }
int Ardb::HSet(Context& ctx, RedisCommandFrame& cmd) { ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); Data field(cmd.GetArguments()[1]), value(cmd.GetArguments()[2]); HashSet(ctx, meta, field, value); //fill_int_reply(ctx.reply, err); return 0; }
int Ardb::LRange(Context& ctx, RedisCommandFrame& cmd) { int64 start, end; if (!GetInt64Value(ctx, cmd.GetArguments()[1], start) || !GetInt64Value(ctx, cmd.GetArguments()[2], end)) { return 0; } ctx.reply.type = REDIS_REPLY_ARRAY; ListRange(ctx, cmd.GetArguments()[0], start, end); return 0; }
int Ardb::Expireat(Context& ctx, RedisCommandFrame& cmd) { uint32 v = 0; if (!check_uint32_arg(ctx.reply, cmd.GetArguments()[1], v)) { return 0; } int err = GenericExpire(ctx, cmd.GetArguments()[0], v * 1000); fill_int_reply(ctx.reply, err == 0 ? 1 : 0); return 0; }
int Ardb::Expire(Context& ctx, RedisCommandFrame& cmd) { uint64 v = 0; if (!check_uint64_arg(ctx.reply, cmd.GetArguments()[1], v)) { return 0; } int err = GenericExpire(ctx, cmd.GetArguments()[0], v * 1000 + get_current_epoch_millis()); fill_int_reply(ctx.reply, err == 0 ? 1 : 0); return 0; }
int ArdbServer::MGet(ArdbConnContext& ctx, RedisCommandFrame& cmd) { SliceArray keys; for (uint32 i = 0; i < cmd.GetArguments().size(); i++) { keys.push_back(cmd.GetArguments()[i]); } StringArray res; m_db->MGet(ctx.currentDB, keys, res); fill_str_array_reply(ctx.reply, res); return 0; }
int ArdbServer::SetRange(ArdbConnContext& ctx, RedisCommandFrame& cmd) { int32 offset; if (!string_toint32(cmd.GetArguments()[1], offset)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } int ret = m_db->SetRange(ctx.currentDB, cmd.GetArguments()[0], offset, cmd.GetArguments()[2]); fill_int_reply(ctx.reply, ret); return 0; }
int ArdbServer::PSetEX(ArdbConnContext& ctx, RedisCommandFrame& cmd) { uint32 mills; if (!string_touint32(cmd.GetArguments()[1], mills)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } m_db->PSetEx(ctx.currentDB, cmd.GetArguments()[0], cmd.GetArguments()[2], mills); fill_status_reply(ctx.reply, "OK"); return 0; }
int Ardb::PExpire(Context& ctx, RedisCommandFrame& cmd) { uint32 v = 0; if (!check_uint32_arg(ctx.reply, cmd.GetArguments()[1], v)) { return 0; } ValueObject meta; int err = GenericExpire(ctx, cmd.GetArguments()[0], v + get_current_epoch_millis()); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); fill_int_reply(ctx.reply, err == 0 ? 1 : 0); return 0; }
int ArdbServer::GetRange(ArdbConnContext& ctx, RedisCommandFrame& cmd) { int32 start, end; if (!string_toint32(cmd.GetArguments()[1], start) || !string_toint32(cmd.GetArguments()[2], end)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } std::string v; m_db->GetRange(ctx.currentDB, cmd.GetArguments()[0], start, end, v); fill_str_reply(ctx.reply, v); return 0; }
int Ardb::HDel(Context& ctx, RedisCommandFrame& cmd) { ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); int count = 0; if (err == 0) { BatchWriteGuard guard(GetKeyValueEngine()); for (uint32 i = 1; i < cmd.GetArguments().size(); i++) { Data field(cmd.GetArguments()[i]); Data value; err = HashGet(ctx, meta, field, value); if (err == 0) { if (meta.meta.encoding != COLLECTION_ECODING_ZIPMAP) { KeyObject k; k.db = ctx.currentDB; k.key = cmd.GetArguments()[0]; k.type = HASH_FIELD; k.element = field; DelKeyValue(ctx, k); if (meta.meta.len > 0) { meta.meta.len--; } } else { meta.meta.zipmap.erase(field); } count++; } } if (count > 0) { if (meta.meta.Length() != 0) { SetKeyValue(ctx, meta); } else { DelKeyValue(ctx, meta.key); } } } fill_int_reply(ctx.reply, count); return 0; }
int ArdbServer::GetSet(ArdbConnContext& ctx, RedisCommandFrame& cmd) { std::string v; int ret = m_db->GetSet(ctx.currentDB, cmd.GetArguments()[0], cmd.GetArguments()[1], v); if (ret < 0) { ctx.reply.type = REDIS_REPLY_NIL; } else { fill_str_reply(ctx.reply, v); } return 0; }
int Ardb::Watch(Context& ctx, RedisCommandFrame& cmd) { if (ctx.InTransc()) { fill_error_reply(ctx.reply, "WATCH inside MULTI is not allowed"); return 0; } for (uint32 i = 0; i < cmd.GetArguments().size(); i++) { WatchForKey(ctx, cmd.GetArguments()[i]); } fill_status_reply(ctx.reply, "OK"); return 0; }
int Comms::BLPop(Context& ctx, RedisCommandFrame& cmd) { uint32 timeout; if (!string_touint32(cmd.GetArguments()[cmd.GetArguments().size() - 1], timeout)) { fill_error_reply(ctx.reply, "timeout is not an integer or out of range"); return 0; } bool lpop = cmd.GetType() == REDIS_CMD_BLPOP; for (uint32 i = 0; i < cmd.GetArguments().size() - 1; i++) { std::string v; int err = lpop ? m_kv_store->LPop(ctx.currentDB, cmd.GetArguments()[i], v) : m_kv_store->RPop(ctx.currentDB, cmd.GetArguments()[i], v); if (0 == err && !v.empty()) { RedisReply& r1 = ctx.reply.AddMember(); RedisReply& r2 = ctx.reply.AddMember(); fill_str_reply(r1, cmd.GetArguments()[i]); fill_str_reply(r2, v); FireKeyChangedEvent(ctx, ctx.currentDB, cmd.GetArguments()[i]); RedisCommandFrame list_pop(lpop ? "lpop" : "rpop"); list_pop.AddArg(cmd.GetArguments()[i]); RewriteClientCommand(ctx, list_pop); return 0; } if (err != 0 && err != mmkv::ERR_ENTRY_NOT_EXIST && err != mmkv::ERR_DB_NOT_EXIST) { FillErrorReply(ctx, err); return 0; } } if (NULL != ctx.client) { ctx.client->DetachFD(); ctx.GetBlockContext().lpop = cmd.GetType() == REDIS_CMD_BLPOP; if (timeout > 0) { ctx.block->blocking_timer_task_id = ctx.client->GetService().GetTimer().ScheduleHeapTask( new BlockListTimeout(&ctx), timeout, -1, SECONDS); } } for (uint32 i = 0; i < cmd.GetArguments().size() - 1; i++) { AddBlockKey(ctx, cmd.GetArguments()[i]); } return 0; }
int Ardb::LPush(Context& ctx, RedisCommandFrame& cmd) { ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); KeyLockerGuard lock(m_key_lock, ctx.currentDB, cmd.GetArguments()[0]); BatchWriteGuard guard(GetKeyValueEngine(), cmd.GetArguments().size() > 2); for (uint32 i = 1; i < cmd.GetArguments().size(); i++) { ListInsert(ctx, meta, NULL, cmd.GetArguments()[i], true, false); } SetKeyValue(ctx, meta); return 0; }
int Ardb::Del(Context& ctx, RedisCommandFrame& cmd) { if (ctx.IsSlave() && m_cfg.slave_ignore_del) { return 0; } BatchWriteGuard guard(GetKeyValueEngine()); int count = 0; for (uint32 i = 0; i < cmd.GetArguments().size(); i++) { count += DeleteKey(ctx, cmd.GetArguments()[i]); } fill_int_reply(ctx.reply, count); return 0; }
//===================================encoder============================== bool RedisCommandEncoder::Encode(Buffer& buf, const RedisCommandFrame& cmd) { buf.Printf("*%d\r\n", cmd.GetArguments().size() + 1); buf.Printf("$%d\r\n", cmd.GetCommand().size()); buf.Write(cmd.GetCommand().data(), cmd.GetCommand().size()); buf.Write("\r\n", 2); for (uint32 i = 0; i < cmd.GetArguments().size(); i++) { const std::string* arg = cmd.GetArgument(i); buf.Printf("$%d\r\n", arg->size()); buf.Write(arg->data(), arg->size()); buf.Write("\r\n", 2); } return true; }
int ArdbServer::GeoSearch(ArdbConnContext& ctx, RedisCommandFrame& cmd) { GeoSearchOptions options; std::string err; if (0 != options.Parse(cmd.GetArguments(), err, 1)) { fill_error_reply(ctx.reply, "%s", err.c_str()); return 0; } ValueDataDeque res; int ret = m_db->GeoSearch(ctx.currentDB, cmd.GetArguments()[0], options, res); CHECK_ARDB_RETURN_VALUE(ctx.reply, ret); fill_array_reply(ctx.reply, res); return 0; }