void Ardb::ClearBlockKeys(Context& ctx) { if (NULL != ctx.block) { if (ctx.block->blocking_timer_task_id != -1) { ctx.client->GetService().GetTimer().Cancel(ctx.block->blocking_timer_task_id); } WatchKeySet::iterator it = ctx.GetBlockContext().keys.begin(); while (it != ctx.GetBlockContext().keys.end()) { WriteLockGuard<SpinRWLock> guard(m_block_ctx_lock); BlockContextTable::iterator fit = m_block_context_table.find(*it); if (fit != m_block_context_table.end()) { fit->second.erase(std::remove(fit->second.begin(), fit->second.end(), &ctx), fit->second.end()); if (fit->second.empty()) { m_block_context_table.erase(fit); } } } ctx.ClearBlockContext(); } }
void Ardb::AddBlockKey(Context& ctx, const std::string& key) { DBItemKey kk(ctx.currentDB, key); ctx.GetBlockContext().keys.insert(kk); WriteLockGuard<SpinRWLock> guard(m_block_ctx_lock); m_block_context_table[kk].push_back(&ctx); }
int Comms::BRPopLPush(Context& ctx, RedisCommandFrame& cmd) { uint32 timeout; if (!string_touint32(cmd.GetArguments()[cmd.GetArguments().size() - 1], timeout)) { fill_error_reply(ctx.reply, "timeout is not an integer or out of range"); return 0; } RPopLPush(ctx, cmd); if (ctx.reply.type == REDIS_REPLY_NIL) { //block; AddBlockKey(ctx, cmd.GetArguments()[0]); ctx.GetBlockContext().lpop = false; ctx.GetBlockContext().push_key = cmd.GetArguments()[1]; if (NULL != ctx.client) { ctx.client->DetachFD(); if (timeout > 0) { ctx.block->blocking_timer_task_id = ctx.client->GetService().GetTimer().ScheduleHeapTask( new BlockListTimeout(&ctx), timeout, -1, SECONDS); } } ctx.reply.type = 0; } return 0; }
void Comms::AddBlockKey(Context& ctx, const std::string& keystr) { WatchKey key(ctx.currentDB, keystr); WriteLockGuard<SpinRWLock> guard(m_block_ctx_lock); ctx.GetBlockContext().keys.insert(key); m_block_context_table[key].insert(&ctx); }
void Comms::WakeBlockedList(Context& ctx, const std::string& key) { std::string v; int err = ctx.GetBlockContext().lpop ? m_kv_store->LPop(ctx.currentDB, key, v) : m_kv_store->RPop(ctx.currentDB, key, v); if (0 == err && !v.empty()) { if (ctx.GetBlockContext().push_key.empty()) { RedisReply& r1 = ctx.reply.AddMember(); RedisReply& r2 = ctx.reply.AddMember(); fill_str_reply(r1, key); fill_str_reply(r2, v); if (!ctx.flags.no_wal) { RedisCommandFrame list_pop(ctx.GetBlockContext().lpop ? "lpop" : "rpop"); list_pop.AddArg(key); m_repl.WriteWAL(ctx.currentDB, list_pop); } } else { err = m_kv_store->RPush(ctx.currentDB, ctx.GetBlockContext().push_key, v); if (err < 0) { ctx.GetBlockContext().lpop ? m_kv_store->LPush(ctx.currentDB, key, v) : m_kv_store->RPush(ctx.currentDB, key, v); FillErrorReply(ctx, err); } else { fill_str_reply(ctx.reply, v); if (!ctx.flags.no_wal) { RedisCommandFrame rpoplpush("rpoplpush"); rpoplpush.AddArg(key); m_repl.WriteWAL(ctx.currentDB, rpoplpush); } } } ctx.client->Write(ctx.reply); ctx.client->AttachFD(); ClearBlockKeys(ctx); } }
int Comms::BLPop(Context& ctx, RedisCommandFrame& cmd) { uint32 timeout; if (!string_touint32(cmd.GetArguments()[cmd.GetArguments().size() - 1], timeout)) { fill_error_reply(ctx.reply, "timeout is not an integer or out of range"); return 0; } bool lpop = cmd.GetType() == REDIS_CMD_BLPOP; for (uint32 i = 0; i < cmd.GetArguments().size() - 1; i++) { std::string v; int err = lpop ? m_kv_store->LPop(ctx.currentDB, cmd.GetArguments()[i], v) : m_kv_store->RPop(ctx.currentDB, cmd.GetArguments()[i], v); if (0 == err && !v.empty()) { RedisReply& r1 = ctx.reply.AddMember(); RedisReply& r2 = ctx.reply.AddMember(); fill_str_reply(r1, cmd.GetArguments()[i]); fill_str_reply(r2, v); FireKeyChangedEvent(ctx, ctx.currentDB, cmd.GetArguments()[i]); RedisCommandFrame list_pop(lpop ? "lpop" : "rpop"); list_pop.AddArg(cmd.GetArguments()[i]); RewriteClientCommand(ctx, list_pop); return 0; } if (err != 0 && err != mmkv::ERR_ENTRY_NOT_EXIST && err != mmkv::ERR_DB_NOT_EXIST) { FillErrorReply(ctx, err); return 0; } } if (NULL != ctx.client) { ctx.client->DetachFD(); ctx.GetBlockContext().lpop = cmd.GetType() == REDIS_CMD_BLPOP; if (timeout > 0) { ctx.block->blocking_timer_task_id = ctx.client->GetService().GetTimer().ScheduleHeapTask( new BlockListTimeout(&ctx), timeout, -1, SECONDS); } } for (uint32 i = 0; i < cmd.GetArguments().size() - 1; i++) { AddBlockKey(ctx, cmd.GetArguments()[i]); } return 0; }