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 Ardb::WatchForKey(Context& ctx, const std::string& key) { WriteLockGuard<SpinRWLock> guard(m_watched_keys_lock); if (NULL == m_watched_ctx) { m_watched_ctx = new WatchedContextTable; } DBItemKey k(ctx.currentDB, key); (*m_watched_ctx)[k].insert(&ctx); ctx.GetTransc().watched_keys.insert(k); return 0; }
int Ardb::Exec(Context& ctx, RedisCommandFrame& cmd) { if (!ctx.InTransc()) { fill_error_reply(ctx.reply, "EXEC without MULTI"); return 0; } if (ctx.GetTransc().abort) { ctx.reply.type = REDIS_REPLY_NIL; ctx.ClearTransc(); return 0; } LockGuard<ThreadMutex> guard(g_transc_mutex); //only one transc allowed exec at the same time in multi threads RedisCommandFrameArray::iterator it = ctx.GetTransc().cached_cmds.begin(); Context transc_ctx; transc_ctx.currentDB = ctx.currentDB; while (it != ctx.GetTransc().cached_cmds.end()) { RedisReply& r = ctx.reply.AddMember(); RedisCommandHandlerSetting* setting = FindRedisCommandHandlerSetting(*it); if(NULL != setting) { transc_ctx.reply.Clear(); DoCall(transc_ctx, *setting, *it); r.Clone(transc_ctx.reply); } else { fill_error_reply(r, "unknown command '%s'", it->GetCommand().c_str()); } it++; } ctx.currentDB = transc_ctx.currentDB; ctx.ClearTransc(); UnwatchKeys(ctx); return 0; }
int Ardb::UnwatchKeys(Context& ctx) { if(NULL != m_watched_ctx && ctx.transc != NULL) { WriteLockGuard<SpinRWLock> guard(m_watched_keys_lock); WatchKeySet::iterator it = ctx.GetTransc().watched_keys.begin(); while(it != ctx.GetTransc().watched_keys.end()) { (*m_watched_ctx)[*it].erase(&ctx); if((*m_watched_ctx)[*it].size() == 0) { m_watched_ctx->erase(*it); } it++; } ctx.ClearTransc(); if(m_watched_ctx->empty()) { DELETE(m_watched_ctx); } } return 0; }