int Ardb::KeysOperation(Context& ctx, const KeysOptions& options) { KeyObject from; from.db = ctx.currentDB; from.type = KEY_META; std::string::size_type cursor = options.pattern.find("*"); if (cursor == std::string::npos) { from.key = options.pattern; } else { if (options.pattern != "*" && cursor > 0) { from.key = options.pattern.substr(0, cursor); } } Iterator* iter = IteratorKeyValue(from, false); std::string tmpkey; uint32 count = 0; while (NULL != iter && iter->Valid()) { KeyObject kk; if (!decode_key(iter->Key(), kk) || kk.db != ctx.currentDB || kk.type != KEY_META) { break; } tmpkey.clear(); tmpkey.assign(kk.key.data(), kk.key.size()); if ((options.pattern == "*" || stringmatchlen(options.pattern.c_str(), options.pattern.size(), tmpkey.data(), tmpkey.size(), 0) == 1)) { if (options.op == OP_GET) { RedisReply& r = ctx.reply.AddMember(); fill_str_reply(r, tmpkey); } else { count++; } } else { /* * If the '*' is the last char, we can break iteration now */ if (cursor == options.pattern.size() - 1) { break; } } iter->Next(); } DELETE(iter); if (options.op == OP_GET) { ctx.reply.type = REDIS_REPLY_ARRAY; } else { fill_int_reply(ctx.reply, count); } return 0; }
int Ardb::Scan(Context& ctx, RedisCommandFrame& cmd) { StringArray keys; std::string pattern; uint32 limit = 10000; //return max 10000 keys one time if (cmd.GetArguments().size() > 1) { for (uint32 i = 1; i < cmd.GetArguments().size(); i++) { if (!strcasecmp(cmd.GetArguments()[i].c_str(), "count")) { if (i + 1 >= cmd.GetArguments().size() || !string_touint32(cmd.GetArguments()[i + 1], limit)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } i++; } else if (!strcasecmp(cmd.GetArguments()[i].c_str(), "match")) { if (i + 1 >= cmd.GetArguments().size()) { fill_error_reply(ctx.reply, "'MATCH' need one args followed"); return 0; } pattern = cmd.GetArguments()[i + 1]; i++; } else { fill_error_reply(ctx.reply, "Syntax error, try scan 0 "); return 0; } } } RedisReply& r1 = ctx.reply.AddMember(); RedisReply& r2 = ctx.reply.AddMember(); r2.type = REDIS_REPLY_ARRAY; KeyObject from; from.db = ctx.currentDB; from.type = KEY_META; const std::string& cursor = cmd.GetArguments()[0]; std::string scan_start_cursor; if (cmd.GetArguments()[0] != "0") { if (m_cfg.scan_redis_compatible) { FindElementByRedisCursor(cursor, scan_start_cursor); } from.key = scan_start_cursor; } Iterator* iter = IteratorKeyValue(from, false); bool reachend = false; std::string tmpkey; while (NULL != iter && iter->Valid()) { KeyObject kk; if (!decode_key(iter->Key(), kk) || kk.db != ctx.currentDB || kk.type != KEY_META) { reachend = true; break; } tmpkey.clear(); tmpkey.assign(kk.key.data(), kk.key.size()); if (r2.MemberSize() >= limit) { break; } if ((pattern.empty() || stringmatchlen(pattern.c_str(), pattern.size(), tmpkey.c_str(), tmpkey.size(), 0) == 1)) { RedisReply& rr1 = r2.AddMember(); fill_str_reply(rr1, tmpkey); } iter->Next(); } if (reachend || !iter->Valid()) { fill_str_reply(r1, "0"); } else { if (m_cfg.scan_redis_compatible) { uint64 newcursor = GetNewRedisCursor(tmpkey); fill_str_reply(r1, stringfromll(newcursor)); } else { fill_str_reply(r1, tmpkey); } } DELETE(iter); return 0; }
int Ardb::Randomkey(Context& ctx, RedisCommandFrame& cmd) { ctx.reply.type = REDIS_REPLY_NIL; KeyObject from; from.db = ctx.currentDB; from.type = KEY_META; std::string min_key, max_key, randkey; Iterator* iter = IteratorKeyValue(from, false); if (iter->Valid()) { KeyObject kk; if (!decode_key(iter->Key(), kk) || kk.db != ctx.currentDB || kk.type != KEY_META) { goto _end; } min_key.assign(kk.key.data(), kk.key.size()); max_key = min_key; from.type = SET_ELEMENT; //Refer comparator.cpp from.encode_buf.Clear(); IteratorSeek(iter, from); if (!iter->Valid()) { iter->SeekToLast(); } if (iter->Valid()) { iter->Prev(); if (iter->Valid()) { if (decode_key(iter->Key(), kk) && kk.db == ctx.currentDB && kk.type == KEY_META) { max_key.assign(kk.key.data(), kk.key.size()); } } } randkey = min_key; if (min_key < max_key) { randkey = random_between_string(min_key, max_key); from.type = KEY_META; from.db = ctx.currentDB; from.key = randkey; IteratorSeek(iter, from); if (iter->Valid()) { KeyObject kk; if (!decode_key(iter->Key(), kk) || kk.db != ctx.currentDB || kk.type != KEY_META) { goto _end; } randkey.assign(kk.key.data(), kk.key.size()); } } } if (!randkey.empty()) { fill_str_reply(ctx.reply, randkey); } _end: DELETE(iter); return 0; }