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 Ardb::LIndex(Context& ctx, RedisCommandFrame& cmd) { int64 index; if (!GetInt64Value(ctx, cmd.GetArguments()[1], index)) { return 0; } ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { ctx.reply.type = REDIS_REPLY_NIL; return 0; } if (meta.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST) { Data* entry = GetZipEntry(meta.meta.ziplist, index); if (NULL != entry) { fill_value_reply(ctx.reply, *entry); } else { ctx.reply.type = REDIS_REPLY_NIL; } return 0; } else { if ((index >= 0 && index >= meta.meta.Length()) || (index < 0 && (meta.meta.Length() + index) < 0)) { ctx.reply.type = REDIS_REPLY_NIL; return 0; } ListIterator iter; if (meta.meta.IsSequentialList()) { err = SequencialListIter(ctx, meta, iter, index); if (0 == err) { if (iter.Valid()) { fill_value_reply(ctx.reply, *(iter.Element())); return 0; } } } else { err = ListIter(ctx, meta, iter, index < 0); uint32 cursor = index < 0 ? 1 : 0; while (iter.Valid()) { if (cursor == std::abs(index)) { fill_value_reply(ctx.reply, *(iter.Element())); return 0; } cursor++; if (index >= 0) { iter.Next(); } else { iter.Prev(); } } } ctx.reply.type = REDIS_REPLY_NIL; } return 0; }
int Ardb::LRem(Context& ctx, RedisCommandFrame& cmd) { int64 count; if (!GetInt64Value(ctx, cmd.GetArguments()[1], count)) { return 0; } int64 toremove = std::abs(count); ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { fill_int_reply(ctx.reply, 0); return 0; } Data element; element.SetString(cmd.GetArguments()[2], true); KeyLockerGuard lock(m_key_lock, ctx.currentDB, cmd.GetArguments()[0]); if (meta.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST) { uint32 oldlen = meta.meta.ziplist.size(); int64 removed = 0; DataArray newzip; if (count >= 0) { for (uint32 i = 0; i < oldlen; i++) { if (meta.meta.ziplist[i] == element) { if (toremove == 0 || removed < toremove) { removed++; continue; } } newzip.push_back(meta.meta.ziplist[i]); } } else { for (uint32 i = 0; i < oldlen; i++) { if (meta.meta.ziplist[oldlen - 1 - i] == element) { if (toremove == 0 || removed < toremove) { removed++; continue; } } newzip.push_front(meta.meta.ziplist[i]); } } if (removed > 0) { meta.meta.ziplist = newzip; SetKeyValue(ctx, meta); } fill_int_reply(ctx.reply, removed); return 0; } BatchWriteGuard guard(GetKeyValueEngine()); ListIterator iter; ListIter(ctx, meta, iter, count < 0); int64 remove = 0; while (iter.Valid()) { if (iter.Element()->Compare(element) == 0) { meta.meta.len--; meta.meta.SetFlag(COLLECTION_FLAG_NORMAL); DelRaw(ctx, iter.CurrentRawKey()); //DelKeyValue(ctx, k); remove++; if (remove == toremove) { break; } } if (count < 0) { iter.Prev(); } else { iter.Next(); } } if (remove > 0) { SetKeyValue(ctx, meta); } fill_int_reply(ctx.reply, remove); 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; } }