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; }
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; }
int Ardb::PUnsubscribeChannel(Context& ctx, const std::string& pattern, bool notify) { ctx.GetPubsub().pubsub_patterns.erase(pattern); WriteLockGuard<SpinRWLock> guard(m_pubsub_ctx_lock); PubsubContextTable::iterator it = m_pubsub_patterns.find(pattern); int ret = 0; if (it != m_pubsub_patterns.end()) { it->second.erase(&ctx); if (it->second.empty()) { m_pubsub_patterns.erase(it); } ret = 1; } if (notify && NULL != ctx.client) { RedisReply r; RedisReply& r1 = r.AddMember(); RedisReply& r2 = r.AddMember(); RedisReply& r3 = r.AddMember(); fill_str_reply(r1, "punsubscribe"); fill_str_reply(r2, pattern); fill_int_reply(r3, ctx.GetPubsub().pubsub_channels.size() + ctx.GetPubsub().pubsub_patterns.size()); ctx.client->Write(r); } return ret; }
/* * 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; }
int Ardb::ListLen(Context& ctx, const Slice& key) { ValueObject meta; int err = GetMetaValue(ctx, key, LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); fill_int_reply(ctx.reply, meta.meta.Length()); return 0; }
int Ardb::Publish(Context& ctx, RedisCommandFrame& cmd) { const std::string& channel = cmd.GetArguments()[0]; const std::string& message = cmd.GetArguments()[1]; int count = 0; count += PublishMessage(ctx, channel, message); fill_int_reply(ctx.reply, count); return 0; }
int Ardb::TTL(Context& ctx, RedisCommandFrame& cmd) { uint64 ms; int err = GenericTTL(ctx, cmd.GetArguments()[0], ms); if (0 == err) { fill_int_reply(ctx.reply, (ms - get_current_epoch_millis()) / 1000); } 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 Ardb::GenericTTL(Context& ctx, const Slice& key, uint64& ms) { ValueObject meta; int err = GetMetaValue(ctx, key, KEY_END, meta); if (0 != err) { if (err == ERR_NOT_EXIST) { fill_int_reply(ctx.reply, -2); } return err; } ms = meta.meta.expireat; if (0 == ms) { fill_int_reply(ctx.reply, -1); return -1; } 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; }
void fill_int_array_reply(RedisReply& reply, T& v) { reply.type = REDIS_REPLY_ARRAY; typename T::iterator it = v.begin(); while (it != v.end()) { RedisReply r; fill_int_reply(r, *it); reply.elements.push_back(r); it++; } }
int Comms::LLen(Context& ctx, RedisCommandFrame& cmd) { int err = m_kv_store->LLen(ctx.currentDB, cmd.GetArguments()[0]); if (err >= 0) { fill_int_reply(ctx.reply, err); } else { FillErrorReply(ctx, err); } 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 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::Decr(ArdbConnContext& ctx, RedisCommandFrame& cmd) { int64_t val; int ret = m_db->Decr(ctx.currentDB, cmd.GetArguments()[0], 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; }
int ArdbServer::Append(ArdbConnContext& ctx, RedisCommandFrame& cmd) { const std::string& key = cmd.GetArguments()[0]; const std::string& value = cmd.GetArguments()[1]; int ret = m_db->Append(ctx.currentDB, key, value); if (ret > 0) { fill_int_reply(ctx.reply, ret); } else { fill_error_reply(ctx.reply, "failed to append key:%s", key.c_str()); } 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; }
int Ardb::ListInsert(Context& ctx, const std::string& key, const std::string* match, const std::string& value, bool head, bool abort_nonexist) { ValueObject meta; int err = GetMetaValue(ctx, key, LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); BatchWriteGuard guard(GetKeyValueEngine(), meta.meta.Encoding() != COLLECTION_ENCODING_ZIPLIST); if (0 != err && abort_nonexist) { fill_int_reply(ctx.reply, 0); return 0; } ListInsert(ctx, meta, match, value, head, abort_nonexist); SetKeyValue(ctx, meta); return 0; }
int Comms::Persist(Context& ctx, RedisCommandFrame& cmd) { int err = m_kv_store->Persist(ctx.currentDB, cmd.GetArguments()[0]); if (err >= 0) { if (err > 0) { FireKeyChangedEvent(ctx, cmd.GetArguments()[0]); } fill_int_reply(ctx.reply, err); } else { FillErrorReply(ctx, err); } return 0; }
int ArdbServer::MSetNX(ArdbConnContext& ctx, RedisCommandFrame& cmd) { if (cmd.GetArguments().size() % 2 != 0) { fill_error_reply(ctx.reply, "wrong number of arguments for MSETNX"); return 0; } SliceArray keys; SliceArray vals; for (uint32 i = 0; i < cmd.GetArguments().size(); i += 2) { keys.push_back(cmd.GetArguments()[i]); vals.push_back(cmd.GetArguments()[i + 1]); } int count = m_db->MSetNX(ctx.currentDB, keys, vals); fill_int_reply(ctx.reply, count); return 0; }
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; }
int Comms::RPush(Context& ctx, RedisCommandFrame& cmd) { mmkv::DataArray fs; for (uint32 i = 1; i < cmd.GetArguments().size(); i++) { fs.push_back(cmd.GetArguments()[i]); } int err = m_kv_store->RPush(ctx.currentDB, cmd.GetArguments()[0], fs); if (err >= 0) { fill_int_reply(ctx.reply, err); FireKeyChangedEvent(ctx, cmd.GetArguments()[0]); WakeBlockingListsByKey(ctx, cmd.GetArguments()[0]); } else { FillErrorReply(ctx, err); } return 0; }
int Ardb::HSetNX(Context& ctx, RedisCommandFrame& cmd) { 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]); err = HashGet(ctx, meta, field, value); if (err == ERR_NOT_EXIST) { value.SetString(cmd.GetArguments()[2], true); HashSet(ctx, meta, field, value); err = 1; } else { err = 0; } fill_int_reply(ctx.reply, err); return 0; }
int Ardb::SubscribeChannel(Context& ctx, const std::string& channel, bool notify) { ctx.GetPubsub().pubsub_channels.insert(channel); { WriteLockGuard<SpinRWLock> guard(m_pubsub_ctx_lock); m_pubsub_channels[channel].insert(&ctx); } if (notify && NULL != ctx.client) { RedisReply r; RedisReply& r1 = r.AddMember(); RedisReply& r2 = r.AddMember(); RedisReply& r3 = r.AddMember(); fill_str_reply(r1, "subscribe"); fill_str_reply(r2, channel); fill_int_reply(r3, ctx.GetPubsub().pubsub_channels.size() + ctx.GetPubsub().pubsub_patterns.size()); ctx.client->Write(r); } return 0; }
int Comms::Expireat(Context& ctx, RedisCommandFrame& cmd) { uint64 v = 0; if (!check_uint64_arg(ctx.reply, cmd.GetArguments()[1], v)) { return 0; } int err = m_kv_store->PExpireat(ctx.currentDB, cmd.GetArguments()[0], v * 1000); if (err >= 0) { if (err > 0) { FireKeyChangedEvent(ctx, cmd.GetArguments()[0]); } fill_int_reply(ctx.reply, err); } else { FillErrorReply(ctx, err); } return 0; }
int Comms::LRem(Context& ctx, RedisCommandFrame& cmd) { int64 count; if (!GetInt64Value(ctx, cmd.GetArguments()[1], count)) { return 0; } int err = m_kv_store->LRem(ctx.currentDB, cmd.GetArguments()[0], count, cmd.GetArguments()[2]); if (err >= 0) { fill_int_reply(ctx.reply, err); if (err > 0) { FireKeyChangedEvent(ctx, cmd.GetArguments()[0]); } } else { FillErrorReply(ctx, err); } return 0; }
int Comms::Move(Context& ctx, RedisCommandFrame& cmd) { DBID dst = 0; if (!string_touint32(cmd.GetArguments()[1], dst)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } int err = m_kv_store->Move(ctx.currentDB, cmd.GetArguments()[0], dst); if (err >= 0) { if (err > 0) { FireKeyChangedEvent(ctx, cmd.GetArguments()[0]); FireKeyChangedEvent(ctx, dst, cmd.GetArguments()[0]); } fill_int_reply(ctx.reply, err); } else { FillErrorReply(ctx, err); } return 0; }
int Ardb::Move(Context& ctx, RedisCommandFrame& cmd) { DBID dst = 0; if (!string_touint32(cmd.GetArguments()[1], dst)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } RedisCommandFrame exists("Exists"); exists.AddArg(cmd.GetArguments()[0]); Context tmpctx; tmpctx.currentDB = dst; Exists(tmpctx, exists); if (ctx.reply.integer == 1) { fill_int_reply(ctx.reply, 0); return 0; } KeyType type = KEY_END; GetType(ctx, cmd.GetArguments()[0], type); switch (type) { case SET_META: { RenameSet(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } case LIST_META: { RenameList(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } case ZSET_META: { RenameZSet(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } case HASH_META: { RenameHash(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } case STRING_META: { RenameString(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } case BITSET_META: { RenameBitset(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } default: { fill_error_reply(ctx.reply, "Invalid type to move"); break; } } fill_int_reply(ctx.reply, 1); return 0; }
int Ardb::Rename(Context& ctx, RedisCommandFrame& cmd) { bool withnx = cmd.GetType() == REDIS_CMD_RENAMENX; if (withnx) { RedisCommandFrame exists("Exists"); exists.AddArg(cmd.GetArguments()[1]); Exists(ctx, exists); if (ctx.reply.integer == 1) { fill_int_reply(ctx.reply, 0); return 0; } } else { DeleteKey(ctx, cmd.GetArguments()[1]); } KeyType type = KEY_END; GetType(ctx, cmd.GetArguments()[0], type); switch (type) { case SET_META: { RenameSet(ctx, ctx.currentDB, cmd.GetArguments()[0], ctx.currentDB, cmd.GetArguments()[1]); break; } case LIST_META: { RenameList(ctx, ctx.currentDB, cmd.GetArguments()[0], ctx.currentDB, cmd.GetArguments()[1]); break; } case ZSET_META: { RenameZSet(ctx, ctx.currentDB, cmd.GetArguments()[0], ctx.currentDB, cmd.GetArguments()[1]); break; } case HASH_META: { RenameHash(ctx, ctx.currentDB, cmd.GetArguments()[0], ctx.currentDB, cmd.GetArguments()[1]); break; } case STRING_META: { RenameString(ctx, ctx.currentDB, cmd.GetArguments()[0], ctx.currentDB, cmd.GetArguments()[1]); break; } case BITSET_META: { RenameBitset(ctx, ctx.currentDB, cmd.GetArguments()[0], ctx.currentDB, cmd.GetArguments()[1]); break; } default: { fill_error_reply(ctx.reply, "Invalid type to rename"); break; } } if (withnx) { fill_int_reply(ctx.reply, 1); } else { fill_status_reply(ctx.reply, "OK"); } return 0; }