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 ArdbServer::Select(ArdbConnContext& ctx, RedisCommandFrame& cmd) { if (!string_touint32(cmd.GetArguments()[0], ctx.currentDB) || ctx.currentDB > 0xFFFFFF) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } m_clients_holder.ChangeCurrentDB(ctx.conn, ctx.currentDB); fill_status_reply(ctx.reply, "OK"); return 0; }
int Ardb::Discard(Context& ctx, RedisCommandFrame& cmd) { if (!ctx.InTransc()) { fill_error_reply(ctx.reply, "DISCARD without MULTI"); return 0; } ctx.ClearTransc(); fill_status_reply(ctx.reply, "OK"); return 0; }
int Ardb::Multi(Context& ctx, RedisCommandFrame& cmd) { if (ctx.InTransc()) { fill_error_reply(ctx.reply, "MULTI calls can not be nested"); return 0; } ctx.GetTransc().in_transc = true; fill_status_reply(ctx.reply, "OK"); 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::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 ArdbServer::Auth(ArdbConnContext& ctx, RedisCommandFrame& cmd) { if (m_cfg.requirepass.empty()) { fill_error_reply(ctx.reply, "Client sent AUTH, but no password is set"); } else if (m_cfg.requirepass != cmd.GetArguments()[0]) { ctx.authenticated = false; fill_error_reply(ctx.reply, "invalid password"); } else { ctx.authenticated = true; fill_status_reply(ctx.reply, "OK"); } return 0; }
int ArdbServer::MSet(ArdbConnContext& ctx, RedisCommandFrame& cmd) { if (cmd.GetArguments().size() % 2 != 0) { fill_error_reply(ctx.reply, "wrong number of arguments for MSET"); 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]); } m_db->MSet(ctx.currentDB, keys, vals); fill_status_reply(ctx.reply, "OK"); return 0; }
/* * CACHE LOAD|EVICT|STATUS key */ int Ardb::Cache(Context& ctx, RedisCommandFrame& cmd) { int ret = 0; if (!strcasecmp(cmd.GetArguments()[0].c_str(), "load")) { KeyType type = KEY_END; GetType(ctx, cmd.GetArguments()[1], type); if (type != KEY_END) { CacheLoadOptions options; options.deocode_geo = true; ret = m_cache.Load(ctx.currentDB, cmd.GetArguments()[1], type, options); } else { ret = ERR_INVALID_TYPE; } } else if (!strcasecmp(cmd.GetArguments()[0].c_str(), "evict")) { ret = m_cache.Evict(ctx.currentDB, cmd.GetArguments()[1]); } else if (!strcasecmp(cmd.GetArguments()[0].c_str(), "status")) { std::string status = m_cache.Status(ctx.currentDB, cmd.GetArguments()[1]); fill_str_reply(ctx.reply, status); return 0; } else { fill_error_reply(ctx.reply, "Syntax error, try CACHE (LOAD | EVICT | STATUS) key"); return 0; } if (ret == 0) { fill_status_reply(ctx.reply, "OK"); } else { fill_error_reply(ctx.reply, "Failed to cache load/evict/status key:%s", cmd.GetArguments()[1].c_str()); } return 0; }
int Ardb::Type(Context& ctx, RedisCommandFrame& cmd) { KeyType type = KEY_END; GetType(ctx, cmd.GetArguments()[0], type); switch (type) { case SET_META: { fill_status_reply(ctx.reply, "set"); break; } case LIST_META: { fill_status_reply(ctx.reply, "list"); break; } case ZSET_META: { fill_status_reply(ctx.reply, "zset"); break; } case HASH_META: { fill_status_reply(ctx.reply, "hash"); break; } case STRING_META: { fill_status_reply(ctx.reply, "string"); break; } case BITSET_META: { fill_status_reply(ctx.reply, "bitset"); break; } default: { fill_status_reply(ctx.reply, "none"); break; } } return 0; }
int Comms::Type(Context& ctx, RedisCommandFrame& cmd) { int type = m_kv_store->Type(ctx.currentDB, cmd.GetArguments()[0]); switch (type) { case mmkv::V_TYPE_SET: { fill_status_reply(ctx.reply, "set"); break; } case mmkv::V_TYPE_LIST: { fill_status_reply(ctx.reply, "list"); break; } case mmkv::V_TYPE_ZSET: { fill_status_reply(ctx.reply, "zset"); break; } case mmkv::V_TYPE_HASH: { fill_status_reply(ctx.reply, "hash"); break; } case mmkv::V_TYPE_STRING: { fill_status_reply(ctx.reply, "string"); break; } case mmkv::V_TYPE_POD: { fill_status_reply(ctx.reply, "pod"); break; } default: { fill_status_reply(ctx.reply, "none"); break; } } return 0; }
/* * GEOADD key MERCATOR|WGS84 x y value [attr_name attr_value ...] */ int ArdbServer::GeoAdd(ArdbConnContext& 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; } int ret = m_db->GeoAdd(ctx.currentDB, cmd.GetArguments()[0], options); CHECK_ARDB_RETURN_VALUE(ctx.reply, ret); if (ret >= 0) { fill_status_reply(ctx.reply, "OK"); } else { fill_error_reply(ctx.reply, "Failed to %s", cmd.ToString().c_str()); } return 0; }
int Ardb::HReplace(Context& ctx, RedisCommandFrame& cmd) { if ((cmd.GetArguments().size() - 1) % 2 != 0) { fill_error_reply(ctx.reply, "wrong number of arguments for HReplace"); return 0; } ValueObject meta; meta.key.db = ctx.currentDB; meta.key.key = cmd.GetArguments()[0]; meta.key.type = KEY_META; meta.type = HASH_META; meta.meta.encoding = COLLECTION_ECODING_ZIPMAP; 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; } meta.attach.force_zipsave = true; HashMultiSet(ctx, meta, fs); fill_status_reply(ctx.reply, "OK"); 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; }
int ArdbServer::Quit(ArdbConnContext& ctx, RedisCommandFrame& cmd) { fill_status_reply(ctx.reply, "OK"); return -1; }
int Ardb::LTrim(Context& ctx, RedisCommandFrame& cmd) { int64 start, end; if (!GetInt64Value(ctx, cmd.GetArguments()[1], start) || !GetInt64Value(ctx, cmd.GetArguments()[2], end)) { return 0; } ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { fill_status_reply(ctx.reply, "OK"); return 0; } /* convert negative indexes */ if (start < 0) start = meta.meta.Length() + start; if (end < 0) end = meta.meta.Length() + end; if (start < 0) start = 0; if (end >= meta.meta.Length()) end = meta.meta.Length() - 1; /* Invariant: start >= 0, so this test will be true when end < 0. * The range is empty when start > end or start >= length. */ if (start > end || start >= meta.meta.Length()) { /* Out of range start or start > end result in empty list */ DeleteKey(ctx, cmd.GetArguments()[0]); return 0; } if (meta.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST) { DataArray newzip; for (int64 i = start; i <= end; i++) { newzip.push_back(meta.meta.ziplist[i]); } meta.meta.ziplist = newzip; SetKeyValue(ctx, meta); } else { BatchWriteGuard guard(GetKeyValueEngine()); if (meta.meta.IsSequentialList()) { int64 listlen = meta.meta.Length(); for (int64 s = 0; s < listlen; s++) { if (s == start) { s = end; continue; } KeyObject lk; lk.db = meta.key.db; lk.key = meta.key.key; lk.type = LIST_ELEMENT; lk.score = meta.meta.min_index.IncrBy(s); meta.meta.len--; DelKeyValue(ctx, lk); } meta.meta.max_index = meta.meta.min_index; meta.meta.min_index.IncrBy(start); meta.meta.max_index.IncrBy(end); } else { ListIterator iter; ListIter(ctx, meta, iter, false); int64 cursor = 0; while (iter.Valid()) { if (cursor < start || cursor > end) { DelRaw(ctx, iter.CurrentRawKey()); meta.meta.len--; } if (cursor == start) { meta.meta.min_index = *(iter.Element()); } else if (cursor == end) { meta.meta.max_index = *(iter.Element()); } cursor++; iter.Next(); } } SetKeyValue(ctx, meta); } return 0; }
int Ardb::LSet(Context& ctx, RedisCommandFrame& cmd) { int64 index; if (!GetInt64Value(ctx, cmd.GetArguments()[1], index)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { fill_error_reply(ctx.reply, "no such key"); return 0; } if (meta.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST) { Data* entry = GetZipEntry(meta.meta.ziplist, index); if (NULL == entry) { fill_error_reply(ctx.reply, "index out of range"); return 0; } else { entry->SetString(cmd.GetArguments()[2], true); SetKeyValue(ctx, meta); fill_status_reply(ctx.reply, "OK"); return 0; } } else { if (index >= meta.meta.Length() || (-index) > meta.meta.Length()) { fill_error_reply(ctx.reply, "index out of range"); return 0; } if (meta.meta.IsSequentialList()) { ValueObject list_element; list_element.key.db = meta.key.db; list_element.key.key = meta.key.key; list_element.key.type = LIST_ELEMENT; list_element.key.score = meta.meta.min_index; if (index >= 0) { list_element.key.score.IncrBy(index); } else { list_element.key.score.IncrBy(index + meta.meta.Length()); } if (0 == GetKeyValue(ctx, list_element.key, &list_element)) { list_element.element.SetString(cmd.GetArguments()[2], true); SetKeyValue(ctx, list_element); fill_status_reply(ctx.reply, "OK"); return 0; } } else { ListIterator iter; ListIter(ctx, meta, iter, index < 0); int64 cursor = index >= 0 ? 0 : -1; while (iter.Valid()) { if (cursor == index) { ValueObject v; v.key.db = meta.key.db; v.key.key = meta.key.key; v.key.type = LIST_ELEMENT; v.key.score = *(iter.Score()); v.type = LIST_ELEMENT; v.element.SetString(cmd.GetArguments()[2], true); SetKeyValue(ctx, v); fill_status_reply(ctx.reply, "OK"); return 0; } if (cursor >= 0) { cursor++; } else { cursor--; } if (index < 0) { iter.Prev(); } else { iter.Next(); } } } fill_error_reply(ctx.reply, "index out of range"); } return 0; }
int ArdbServer::Ping(ArdbConnContext& ctx, RedisCommandFrame& cmd) { fill_status_reply(ctx.reply, "PONG"); return 0; }
int ArdbServer::Set(ArdbConnContext& ctx, RedisCommandFrame& cmd) { const std::string& key = cmd.GetArguments()[0]; const std::string& value = cmd.GetArguments()[1]; int ret = 0; if (cmd.GetArguments().size() == 2) { ret = m_db->Set(ctx.currentDB, key, value); } else { uint32 i = 0; uint64 px = 0, ex = 0; for (i = 2; i < cmd.GetArguments().size(); i++) { std::string tmp = string_tolower(cmd.GetArguments()[i]); if (tmp == "ex" || tmp == "px") { int64 iv; if (!raw_toint64(cmd.GetArguments()[i + 1].c_str(), cmd.GetArguments()[i + 1].size(), iv) || iv < 0) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } if (tmp == "px") { px = iv; } else { ex = iv; } i++; } else { break; } } bool hasnx = false, hasxx = false; bool syntaxerror = false; if (i < cmd.GetArguments().size() - 1) { syntaxerror = true; } if (i == cmd.GetArguments().size() - 1) { std::string cmp = string_tolower(cmd.GetArguments()[i]); if (cmp != "nx" && cmp != "xx") { syntaxerror = true; } else { hasnx = cmp == "nx"; hasxx = cmp == "xx"; } } if (syntaxerror) { fill_error_reply(ctx.reply, "syntax error"); return 0; } int nxx = 0; if (hasnx) { nxx = -1; } if (hasxx) { nxx = 1; } ret = m_db->Set(ctx.currentDB, key, value, ex, px, nxx); } if (0 == ret) { fill_status_reply(ctx.reply, "OK"); } else { switch (ret) { case ERR_INVALID_TYPE: { fill_error_reply(ctx.reply, "invalid type"); break; } case ERR_KEY_EXIST: case ERR_NOT_EXIST: { ctx.reply.type = REDIS_REPLY_NIL; break; } default: { fill_error_reply(ctx.reply, "set failed"); break; } } } return 0; }
int Ardb::UnWatch(Context& ctx, RedisCommandFrame& cmd) { fill_status_reply(ctx.reply, "OK"); UnwatchKeys(ctx); return 0; }