int Ardb::DeleteKey(Context& ctx, const Slice& key) { ValueObject meta; meta.key.type = KEY_META; meta.key.db = ctx.currentDB; meta.key.key = key; if (0 != GetKeyValue(ctx, meta.key, &meta)) { return 0; } switch (meta.type) { case SET_META: { SClear(ctx, meta); break; } case LIST_META: { LClear(ctx, meta); break; } case ZSET_META: { ZClear(ctx, meta); break; } case HASH_META: { HClear(ctx, meta); break; } case STRING_META: { DelKeyValue(ctx, meta.key); break; } case BITSET_META: { BitClear(ctx, meta); break; } default: { return 0; } } if (meta.meta.expireat > 0) { KeyObject expire; expire.type = KEY_EXPIRATION_ELEMENT; expire.db = ctx.currentDB; expire.key = key; expire.score.SetInt64(meta.meta.expireat); DelKeyValue(ctx, expire); } return 1; }
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 Ardb::LClear(Context& ctx, ValueObject& meta) { BatchWriteGuard guard(GetKeyValueEngine(), meta.meta.Encoding() != COLLECTION_ENCODING_ZIPLIST); if (meta.meta.Encoding() != COLLECTION_ENCODING_ZIPLIST) { ListIterator iter; meta.meta.len = 0; ListIter(ctx, meta, iter, false); while (iter.Valid()) { KeyObject fk; fk.db = ctx.currentDB; fk.key = meta.key.key; fk.type = LIST_ELEMENT; fk.score = *(iter.Score()); DelKeyValue(ctx, fk); iter.Next(); } } DelKeyValue((ctx), meta.key); return 0; }
int Ardb::HClear(Context& ctx, ValueObject& meta) { BatchWriteGuard guard(GetKeyValueEngine(), meta.meta.encoding != COLLECTION_ECODING_ZIPMAP); if (meta.meta.encoding != COLLECTION_ECODING_ZIPMAP) { HashIterator iter; HashIter(ctx, meta, "", iter, false); while (iter.Valid()) { DelRaw(ctx, iter.CurrentRawKey()); iter.Next(); } } DelKeyValue(ctx, meta.key); return 0; }
int Ardb::RenameList(Context& ctx, DBID srcdb, const std::string& srckey, DBID dstdb, const std::string& dstkey) { Context tmpctx; tmpctx.currentDB = srcdb; ValueObject v; int err = GetMetaValue(tmpctx, srckey, LIST_META, v); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { fill_error_reply(ctx.reply, "no such key or some error"); return 0; } if (v.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST) { DelKeyValue(tmpctx, v.key); v.key.encode_buf.Clear(); v.key.db = dstdb; v.key.key = dstkey; v.meta.expireat = 0; SetKeyValue(ctx, v); } else { ListIterator iter; ListIter(ctx, v, iter, false); tmpctx.currentDB = dstdb; ValueObject dstmeta; dstmeta.key.type = KEY_META; dstmeta.key.key = dstkey; dstmeta.type = LIST_META; dstmeta.meta.SetFlag(COLLECTION_FLAG_SEQLIST); dstmeta.meta.SetEncoding(COLLECTION_ENCODING_ZIPLIST); BatchWriteGuard guard(GetKeyValueEngine()); while (iter.Valid()) { std::string tmpstr; ListInsert(tmpctx, dstmeta, NULL, iter.Element()->GetDecodeString(tmpstr), false, false); iter.Next(); } SetKeyValue(tmpctx, dstmeta); tmpctx.currentDB = srcdb; DeleteKey(tmpctx, srckey); } ctx.data_change = true; return 0; }
int Ardb::GenericExpire(Context& ctx, const Slice& key, uint64 ms) { if (ms > 0 && get_current_epoch_millis() >= ms) { return 0; } if (m_cfg.slave_ignore_expire && ctx.IsSlave()) { /* * ignore expire setting, but issue data change event for replication */ ctx.data_change = true; return 0; } ValueObject meta; int err = GetMetaValue(ctx, key, KEY_END, meta); if (0 != err) { return err; } BatchWriteGuard guard(GetKeyValueEngine()); if (meta.meta.expireat != ms && meta.meta.expireat > 0) { KeyObject expire; expire.key = key; expire.type = KEY_EXPIRATION_ELEMENT; expire.db = ctx.currentDB; expire.score.SetInt64(meta.meta.expireat); DelKeyValue(ctx, expire); } meta.meta.expireat = ms; SetKeyValue(ctx, meta); if (meta.meta.expireat > 0) { ValueObject vv(KEY_EXPIRATION_ELEMENT); vv.key.key = key; vv.key.type = KEY_EXPIRATION_ELEMENT; vv.key.db = ctx.currentDB; vv.key.score.SetInt64(meta.meta.expireat); SetKeyValue(ctx, vv); } return 0; }
int Ardb::RenameHash(Context& ctx, DBID srcdb, const std::string& srckey, DBID dstdb, const std::string& dstkey) { Context tmpctx; tmpctx.currentDB = srcdb; ValueObject v; int err = GetMetaValue(tmpctx, srckey, HASH_META, v); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { fill_error_reply(ctx.reply, "no such key or some error"); return 0; } if (v.meta.encoding == COLLECTION_ECODING_ZIPMAP) { DelKeyValue(tmpctx, v.key); v.key.encode_buf.Clear(); v.key.db = dstdb; v.key.key = dstkey; v.meta.expireat = 0; SetKeyValue(ctx, v); } else { HashIterator iter; HashIter(ctx, v, "", iter, false); tmpctx.currentDB = dstdb; ValueObject dstmeta; dstmeta.key.type = KEY_META; dstmeta.key.key = dstkey; dstmeta.type = HASH_META; dstmeta.meta.encoding = COLLECTION_ECODING_ZIPMAP; BatchWriteGuard guard(GetKeyValueEngine()); while (iter.Valid()) { HashSet(tmpctx, dstmeta, *(iter.Field()), *(iter.Value())); iter.Next(); } SetKeyValue(tmpctx, dstmeta); tmpctx.currentDB = srcdb; DeleteKey(tmpctx, srckey); } ctx.data_change = true; return 0; }
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::ListPop(Context& ctx, const std::string& key, bool lpop) { ValueObject meta; KeyLockerGuard keylock(m_key_lock, ctx.currentDB, key); int err = GetMetaValue(ctx, key, LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { ctx.reply.type = REDIS_REPLY_NIL; return 0; } BatchWriteGuard guard(GetKeyValueEngine(), meta.meta.Encoding() != COLLECTION_ENCODING_ZIPLIST); if (meta.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST) { if (!meta.meta.ziplist.empty()) { if (lpop) { Data& data = meta.meta.ziplist.front(); fill_value_reply(ctx.reply, data); meta.meta.ziplist.pop_front(); } else { Data& data = meta.meta.ziplist.back(); fill_value_reply(ctx.reply, data); meta.meta.ziplist.pop_back(); } if (meta.meta.ziplist.empty()) { DelKeyValue(ctx, meta.key); } else { SetKeyValue(ctx, meta); } } else { ctx.reply.type = REDIS_REPLY_NIL; } return 0; } else { bool poped = false; if (meta.meta.IsSequentialList()) { if (meta.meta.Length() > 0) { ValueObject lkv; lkv.key.type = LIST_ELEMENT; lkv.key.key = meta.key.key; lkv.key.db = ctx.currentDB; lkv.key.score = lpop ? meta.meta.min_index : meta.meta.max_index; if (0 == GetKeyValue(ctx, lkv.key, &lkv)) { DelKeyValue(ctx, lkv.key); if (lpop) { meta.meta.min_index.IncrBy(1); } else { meta.meta.max_index.IncrBy(-1); } meta.meta.len--; poped = true; fill_value_reply(ctx.reply, lkv.element); } } } else { ListIterator iter; err = ListIter(ctx, meta, iter, !lpop); while (iter.Valid()) { if (!poped) { fill_value_reply(ctx.reply, *(iter.Element())); poped = true; meta.meta.len--; KeyObject k; k.type = LIST_ELEMENT; k.key = meta.key.key; k.db = ctx.currentDB; k.score = *(iter.Score()); DelKeyValue(ctx, k); } else { if (lpop) { meta.meta.min_index = *(iter.Score()); } else { meta.meta.max_index = *(iter.Score()); } break; } if (lpop) { iter.Next(); } else { iter.Prev(); } } } if (poped) { if (meta.meta.Length() > 0) { SetKeyValue(ctx, meta); } else { DelKeyValue(ctx, meta.key); } } else { ctx.reply.type = REDIS_REPLY_NIL; } return 0; } }