Ejemplo n.º 1
0
 int Ardb::BRPop(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;
     }
     for (uint32 i = 0; i < cmd.GetArguments().size() - 1; i++)
     {
         if (ListPop(ctx, cmd.GetArguments()[i], false) == 0 && ctx.reply.type == REDIS_REPLY_STRING)
         {
             RedisReply& r1 = ctx.reply.AddMember();
             RedisReply& r2 = ctx.reply.AddMember();
             fill_str_reply(r1, cmd.GetArguments()[i]);
             fill_str_reply(r2, ctx.reply.str);
             return 0;
         }
     }
     for (uint32 i = 0; i < cmd.GetArguments().size() - 1; i++)
     {
         AddBlockKey(ctx, cmd.GetArguments()[i]);
     }
     if (NULL != ctx.client)
     {
         ctx.client->DetachFD();
         if (timeout > 0)
         {
             ctx.block->blocking_timer_task_id = ctx.client->GetService().GetTimer().ScheduleHeapTask(
                     new BlockConnectionTimeout(&ctx), timeout, -1, SECONDS);
         }
     }
     return 0;
 }
Ejemplo n.º 2
0
 int Ardb::UnsubscribeChannel(Context& ctx, const std::string& channel, bool notify)
 {
     ctx.GetPubsub().pubsub_channels.erase(channel);
     WriteLockGuard<SpinRWLock> guard(m_pubsub_ctx_lock);
     PubsubContextTable::iterator it = m_pubsub_channels.find(channel);
     int ret = 0;
     if (it != m_pubsub_channels.end())
     {
         it->second.erase(&ctx);
         if (it->second.empty())
         {
             m_pubsub_channels.erase(it);
         }
         ret = 1;
     }
     if (notify && NULL != ctx.client)
     {
         RedisReply r;
         RedisReply& r1 = r.AddMember();
         RedisReply& r2 = r.AddMember();
         RedisReply& r3 = r.AddMember();
         fill_str_reply(r1, "unsubscribe");
         fill_str_reply(r2, channel);
         fill_int_reply(r3, ctx.GetPubsub().pubsub_channels.size() + ctx.GetPubsub().pubsub_patterns.size());
         ctx.client->Write(r);
     }
     return ret;
 }
Ejemplo n.º 3
0
    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;
    }
Ejemplo n.º 4
0
 void Ardb::WakeBlockedConnCallback(Channel* ch, void* data)
 {
     if (NULL != ch)
     {
         Context* ctx = (Context*) data;
         if (-1 != ctx->block->blocking_timer_task_id)
         {
             ch->GetService().GetTimer().Cancel(ctx->block->blocking_timer_task_id);
             ctx->block->blocking_timer_task_id = -1;
         }
         if (ctx->block->dest_key.empty())
         {
             ctx->reply.type = REDIS_REPLY_ARRAY;
             if (!ctx->block->waked_value.empty())
             {
                 RedisReply& r1 = ctx->reply.AddMember();
                 RedisReply& r2 = ctx->reply.AddMember();
                 fill_str_reply(r1, ctx->block->waked_key.key);
                 fill_str_reply(r2, ctx->block->waked_value);
                 RedisCommandFrame lpop("lpop");
                 lpop.AddArg(ctx->block->waked_key.key);
                 g_db->m_master.FeedSlaves(ctx->currentDB, lpop);
             }
         }
         else
         {
             if (!ctx->block->waked_value.empty())
             {
                 fill_str_reply(ctx->reply, ctx->block->waked_value);
                 RedisCommandFrame lpush("lpush");
                 lpush.AddArg(ctx->block->dest_key);
                 lpush.AddArg(ctx->block->waked_value);
                 g_db->LPush(*ctx, lpush);
                 RedisCommandFrame lpop("lpop");
                 lpop.AddArg(ctx->block->waked_key.key);
                 g_db->m_master.FeedSlaves(ctx->currentDB, lpop);
                 g_db->m_master.FeedSlaves(ctx->currentDB, lpush);
             }
             else
             {
                 ctx->reply.type = REDIS_REPLY_NIL;
             }
         }
         ch->Write(ctx->reply);
         g_db->ClearBlockKeys(*ctx);
         ch->AttachFD();
     }
 }
Ejemplo n.º 5
0
Archivo: t_hash.cpp Proyecto: cvan/ardb
 int Ardb::HIncrbyFloat(Context& ctx, RedisCommandFrame& cmd)
 {
     double increment, val = 0;
     if (!GetDoubleValue(ctx, cmd.GetArguments()[2], increment))
     {
         return 0;
     }
     ValueObject meta;
     int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta);
     CHECK_ARDB_RETURN_VALUE(ctx.reply, err);
     Data value;
     Data field(cmd.GetArguments()[1]);
     if (0 == err)
     {
         HashGet(ctx, meta, field, value);
         if (!value.GetDouble(val))
         {
             fill_error_reply(ctx.reply, "value is not a float or out of range");
             return 0;
         }
     }
     val += increment;
     std::string tmp;
     fast_dtoa(val, 10, tmp);
     value.SetString(tmp, false);
     HashSet(ctx, meta, field, value);
     fill_str_reply(ctx.reply, tmp);
     return 0;
 }
Ejemplo n.º 6
0
OP_NAMESPACE_BEGIN

    int Comms::LIndex(Context& ctx, RedisCommandFrame& cmd)
    {
        int64 index;
        if (!GetInt64Value(ctx, cmd.GetArguments()[1], index))
        {
            return 0;
        }
        std::string v;
        int err = m_kv_store->LIndex(ctx.currentDB, cmd.GetArguments()[0], index, v);
        if (err >= 0)
        {
            fill_str_reply(ctx.reply, v);
        }
        else if (mmkv::ERR_OFFSET_OUTRANGE == err)
        {
            ctx.reply.type = REDIS_REPLY_NIL;
        }
        else
        {
            FillErrorReply(ctx, err);
        }
        return 0;
    }
Ejemplo n.º 7
0
 int Ardb::UnsubscribeAll(Context& ctx, bool notify)
 {
     if(NULL == ctx.pubsub)
     {
         return 0;
     }
     StringSet tmp = ctx.GetPubsub().pubsub_channels;
     StringSet::iterator it = tmp.begin();
     int count = 0;
     while (it != tmp.end())
     {
         count += UnsubscribeChannel(ctx, *it, notify);
         it++;
     }
     if (notify && count == 0 && NULL != ctx.client)
     {
         RedisReply r;
         RedisReply& r1 = r.AddMember();
         RedisReply& r2 = r.AddMember();
         RedisReply& r3 = r.AddMember();
         fill_str_reply(r1, "unsubscribe");
         r2.type = REDIS_REPLY_NIL;
         fill_int_reply(r3, ctx.GetPubsub().pubsub_channels.size() + ctx.GetPubsub().pubsub_patterns.size());
         ctx.client->Write(r);
     }
     return 0;
 }
Ejemplo n.º 8
0
 int Comms::RPopLPush(Context& ctx, RedisCommandFrame& cmd)
 {
     std::string v;
     int err = m_kv_store->RPopLPush(ctx.currentDB, cmd.GetArguments()[0], cmd.GetArguments()[1], v);
     if (err >= 0)
     {
         fill_str_reply(ctx.reply, v);
         FireKeyChangedEvent(ctx, cmd.GetArguments()[0]);
         FireKeyChangedEvent(ctx, cmd.GetArguments()[1]);
         if (cmd.GetType() == REDIS_CMD_BRPOPLPUSH)
         {
             ctx.current_cmd->SetCommand("rpoplpush");
         }
     }
     else
     {
         if (err == mmkv::ERR_ENTRY_NOT_EXIST || err == mmkv::ERR_DB_NOT_EXIST)
         {
             ctx.reply.type = REDIS_REPLY_NIL;
         }
         else
         {
             FillErrorReply(ctx, err);
         }
     }
     return 0;
 }
Ejemplo n.º 9
0
 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);
     }
 }
Ejemplo n.º 10
0
    int Ardb::PublishMessage(Context& ctx, const std::string& channel, const std::string& message)
    {
        ReadLockGuard<SpinRWLock> guard(m_pubsub_ctx_lock);
        PubsubContextTable::iterator fit = m_pubsub_channels.find(channel);

        int receiver = 0;
        if (fit != m_pubsub_channels.end())
        {
            ContextSet::iterator cit = fit->second.begin();
            while (cit != fit->second.end())
            {
                Context* cc = *cit;
                if (NULL != cc && cc->client != NULL)
                {
                    RedisReply* r = NULL;
                    NEW(r, RedisReply);
                    RedisReply& r1 = r->AddMember();
                    RedisReply& r2 = r->AddMember();
                    RedisReply& r3 = r->AddMember();
                    fill_str_reply(r1, "message");
                    fill_str_reply(r2, channel);
                    fill_str_reply(r3, message);
                    cc->client->GetService().AsyncIO(cc->client->GetID(), async_write_message, r);
                    receiver++;
                }
                cit++;
            }
        }
        PubsubContextTable::iterator pit = m_pubsub_patterns.begin();
        while (pit != m_pubsub_patterns.end())
        {
            const std::string& pattern = pit->first;
            if (stringmatchlen(pattern.c_str(), pattern.size(), channel.c_str(), channel.size(), 0))
            {
                ContextSet::iterator cit = pit->second.begin();
                while (cit != pit->second.end())
                {
                    Context* cc = *cit;
                    if (NULL != cc && cc->client != NULL)
                    {
                        RedisReply* r = NULL;
                        NEW(r, RedisReply);
                        RedisReply& r1 = r->AddMember();
                        RedisReply& r2 = r->AddMember();
                        RedisReply& r3 = r->AddMember();
                        RedisReply& r4 = r->AddMember();
                        fill_str_reply(r1, "pmessage");
                        fill_str_reply(r2, pattern);
                        fill_str_reply(r3, channel);
                        fill_str_reply(r4, message);
                        cc->client->GetService().AsyncIO(cc->client->GetID(), async_write_message, r);
                        receiver++;
                    }
                    cit++;
                }
            }
            pit++;
        }
        return receiver;
    }
Ejemplo n.º 11
0
OP_NAMESPACE_BEGIN

    int Comms::Randomkey(Context& ctx, RedisCommandFrame& cmd)
    {
        std::string key;
        m_kv_store->RandomKey(ctx.currentDB, key);
        fill_str_reply(ctx.reply, key);
        return 0;
    }
Ejemplo n.º 12
0
    int Ardb::SubscribeChannel(Context& ctx, const std::string& channel, bool notify)
    {
        ctx.GetPubsub().pubsub_channels.insert(channel);
        {
            WriteLockGuard<SpinRWLock> guard(m_pubsub_ctx_lock);
            m_pubsub_channels[channel].insert(&ctx);
        }

        if (notify && NULL != ctx.client)
        {
            RedisReply r;
            RedisReply& r1 = r.AddMember();
            RedisReply& r2 = r.AddMember();
            RedisReply& r3 = r.AddMember();
            fill_str_reply(r1, "subscribe");
            fill_str_reply(r2, channel);
            fill_int_reply(r3, ctx.GetPubsub().pubsub_channels.size() + ctx.GetPubsub().pubsub_patterns.size());
            ctx.client->Write(r);
        }
        return 0;
    }
Ejemplo n.º 13
0
 void fill_str_array_reply(RedisReply& reply, T& v)
 {
     reply.type = REDIS_REPLY_ARRAY;
     typename T::iterator it = v.begin();
     while (it != v.end())
     {
         RedisReply r;
         fill_str_reply(r, *it);
         reply.elements.push_back(r);
         it++;
     }
 }
Ejemplo n.º 14
0
 int ArdbServer::GetRange(ArdbConnContext& ctx, RedisCommandFrame& cmd)
 {
     int32 start, end;
     if (!string_toint32(cmd.GetArguments()[1], start) || !string_toint32(cmd.GetArguments()[2], end))
     {
         fill_error_reply(ctx.reply, "value is not an integer or out of range");
         return 0;
     }
     std::string v;
     m_db->GetRange(ctx.currentDB, cmd.GetArguments()[0], start, end, v);
     fill_str_reply(ctx.reply, v);
     return 0;
 }
Ejemplo n.º 15
0
 int ArdbServer::GetSet(ArdbConnContext& ctx, RedisCommandFrame& cmd)
 {
     std::string v;
     int ret = m_db->GetSet(ctx.currentDB, cmd.GetArguments()[0], cmd.GetArguments()[1], v);
     if (ret < 0)
     {
         ctx.reply.type = REDIS_REPLY_NIL;
     }
     else
     {
         fill_str_reply(ctx.reply, v);
     }
     return 0;
 }
Ejemplo n.º 16
0
 int Ardb::RPopLPush(Context& ctx, RedisCommandFrame& cmd)
 {
     std::string v;
     if (ListPop(ctx, cmd.GetArguments()[0], false) == 0 && ctx.reply.type == REDIS_REPLY_STRING)
     {
         std::string value = ctx.reply.str;
         ListInsert(ctx, cmd.GetArguments()[1], NULL, ctx.reply.str, false, false);
         fill_str_reply(ctx.reply, value);
     }
     else
     {
         ctx.reply.type = REDIS_REPLY_NIL;
     }
     return 0;
 }
Ejemplo n.º 17
0
 int ArdbServer::Get(ArdbConnContext& ctx, RedisCommandFrame& cmd)
 {
     const std::string& key = cmd.GetArguments()[0];
     std::string value;
     if (0 == m_db->Get(ctx.currentDB, key, value))
     {
         fill_str_reply(ctx.reply, value);
         //ctx.reply.type = REDIS_REPLY_NIL;
     }
     else
     {
         ctx.reply.type = REDIS_REPLY_NIL;
     }
     return 0;
 }
Ejemplo n.º 18
0
Archivo: keys.cpp Proyecto: boreys/ardb
 /*
  * CACHE LOAD|EVICT|STATUS key
  */
 int Ardb::Cache(Context& ctx, RedisCommandFrame& cmd)
 {
     int ret = 0;
     if (!strcasecmp(cmd.GetArguments()[0].c_str(), "load"))
     {
         KeyType type = KEY_END;
         GetType(ctx, cmd.GetArguments()[1], type);
         if (type != KEY_END)
         {
             CacheLoadOptions options;
             options.deocode_geo = true;
             ret = m_cache.Load(ctx.currentDB, cmd.GetArguments()[1], type, options);
         }
         else
         {
             ret = ERR_INVALID_TYPE;
         }
     }
     else if (!strcasecmp(cmd.GetArguments()[0].c_str(), "evict"))
     {
         ret = m_cache.Evict(ctx.currentDB, cmd.GetArguments()[1]);
     }
     else if (!strcasecmp(cmd.GetArguments()[0].c_str(), "status"))
     {
         std::string status = m_cache.Status(ctx.currentDB, cmd.GetArguments()[1]);
         fill_str_reply(ctx.reply, status);
         return 0;
     }
     else
     {
         fill_error_reply(ctx.reply, "Syntax error, try CACHE (LOAD | EVICT | STATUS) key");
         return 0;
     }
     if (ret == 0)
     {
         fill_status_reply(ctx.reply, "OK");
     }
     else
     {
         fill_error_reply(ctx.reply, "Failed to cache load/evict/status key:%s", cmd.GetArguments()[1].c_str());
     }
     return 0;
 }
Ejemplo n.º 19
0
 int Comms::RPop(Context& ctx, RedisCommandFrame& cmd)
 {
     std::string v;
     int err = m_kv_store->RPop(ctx.currentDB, cmd.GetArguments()[0], v);
     if (err >= 0)
     {
         fill_str_reply(ctx.reply, v);
         FireKeyChangedEvent(ctx, cmd.GetArguments()[0]);
     }
     else
     {
         if (err == mmkv::ERR_ENTRY_NOT_EXIST || err == mmkv::ERR_DB_NOT_EXIST)
         {
             ctx.reply.type = REDIS_REPLY_NIL;
         }
         else
         {
             FillErrorReply(ctx, err);
         }
     }
     return 0;
 }
Ejemplo n.º 20
0
 void fill_array_reply(RedisReply& reply, T& v)
 {
     reply.type = REDIS_REPLY_ARRAY;
     typename T::iterator it = v.begin();
     while (it != v.end())
     {
         ValueData& vo = *it;
         RedisReply r;
         if (vo.type == EMPTY_VALUE)
         {
             r.type = REDIS_REPLY_NIL;
         }
         else
         {
             std::string str;
             vo.ToBytes();
             fill_str_reply(r, vo.bytes_value);
         }
         reply.elements.push_back(r);
         it++;
     }
 }
Ejemplo n.º 21
0
Archivo: t_hash.cpp Proyecto: cvan/ardb
 int Ardb::HKeys(Context& ctx, RedisCommandFrame& cmd)
 {
     ValueObject meta;
     int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta);
     CHECK_ARDB_RETURN_VALUE(ctx.reply, err);
     ctx.reply.type = REDIS_REPLY_ARRAY;
     if (0 != err)
     {
         return 0;
     }
     HashIterator iter;
     err = HashIter(ctx, meta, "", iter, true);
     CHECK_ARDB_RETURN_VALUE(ctx.reply, err);
     ctx.reply.type = REDIS_REPLY_ARRAY;
     while (iter.Valid())
     {
         const Data* value = iter.Field();
         RedisReply& r = ctx.reply.AddMember();
         std::string tmp;
         fill_str_reply(r, value->GetDecodeString(tmp));
         iter.Next();
     }
     return 0;
 }
Ejemplo n.º 22
0
    int Ardb::ListRange(Context& ctx, const Slice& key, int64 start, int64 end)
    {
        ValueObject meta;
        int err = GetMetaValue(ctx, key, LIST_META, meta);
        CHECK_ARDB_RETURN_VALUE(ctx.reply, err);
        /* convert negative indexes */
        if (start < 0)
            start = meta.meta.Length() + start;
        if (end < 0)
            end = meta.meta.Length() + end;
        if (start < 0)
            start = 0;

        /* Invariant: start >= 0, so this test will be true when end < 0.
         * The range is empty when start > end or start >= length. */
        ctx.reply.type = REDIS_REPLY_ARRAY;
        if (start > end || start >= meta.meta.Length())
        {
            return 0;
        }
        if (end >= meta.meta.Length())
            end = meta.meta.Length() - 1;
        int64 rangelen = (end - start) + 1;
        if (meta.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST)
        {
            uint32 i = start;
            while (rangelen--)
            {
                RedisReply& r = ctx.reply.AddMember();
                fill_value_reply(r, meta.meta.ziplist[i++]);
            }
        }
        else
        {
            ListIterator iter;
            if (meta.meta.IsSequentialList())
            {
                SequencialListIter(ctx, meta, iter, start);
                uint32 count = 0;
                while (iter.Valid() && count < rangelen)
                {
                    RedisReply& r = ctx.reply.AddMember();
                    fill_str_reply(r, iter.Element()->ToString());
                    count++;
                    iter.Next();
                }
            }
            else
            {
                if (start > meta.meta.len / 2)
                {
                    start -= meta.meta.len;
                    end -= meta.meta.len;
                }

                ListIter(ctx, meta, iter, start < 0);
                int64 cursor = start < 0 ? -1 : 0;
                while (iter.Valid())
                {
                    if (cursor >= start && cursor <= end)
                    {
                        RedisReply& r = ctx.reply.AddMember();
                        fill_str_reply(r, iter.Element()->ToString());
                    }
                    if (start < 0)
                    {
                        if (cursor < start)
                        {
                            break;
                        }
                        cursor--;
                    }
                    else
                    {
                        if (cursor > end)
                        {
                            break;
                        }
                        cursor++;
                    }
                    iter.Next();
                }
            }
        }
        return 0;
    }
Ejemplo n.º 23
0
Archivo: keys.cpp Proyecto: boreys/ardb
    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;
    }
Ejemplo n.º 24
0
Archivo: keys.cpp Proyecto: boreys/ardb
    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;
    }
Ejemplo n.º 25
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;
    }
Ejemplo n.º 26
0
 int ArdbServer::Echo(ArdbConnContext& ctx, RedisCommandFrame& cmd)
 {
     fill_str_reply(ctx.reply, cmd.GetArguments()[0]);
     return 0;
 }
Ejemplo n.º 27
0
Archivo: t_hash.cpp Proyecto: cvan/ardb
    int Ardb::HScan(Context& ctx, RedisCommandFrame& cmd)
    {
        std::string pattern;
        uint32 limit = 10000; //return max 10000 keys one time
        if (cmd.GetArguments().size() > 2)
        {
            for (uint32 i = 2; 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;
                }
            }
        }
        ValueObject meta;
        int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta);
        CHECK_ARDB_RETURN_VALUE(ctx.reply, err);

        RedisReply& r1 = ctx.reply.AddMember();
        RedisReply& r2 = ctx.reply.AddMember();
        r2.type = REDIS_REPLY_ARRAY;
        if (0 != err)
        {
            fill_str_reply(r1, "0");
            return 0;
        }
        const std::string& cursor = cmd.GetArguments()[1];
        HashIterator iter;
        HashIter(ctx, meta, cursor == "0" ? "" : cursor, iter, true);
        while (iter.Valid())
        {
            const Data* field = iter.Field();
            std::string tmp;
            field->GetDecodeString(tmp);
            if ((pattern.empty() || fnmatch(pattern.c_str(), tmp.c_str(), 0) == 0))
            {
                RedisReply& rr1 = r2.AddMember();
                RedisReply& rr2 = r2.AddMember();
                fill_str_reply(rr1, tmp);
                fill_value_reply(rr2, *(iter.Value()));
            }
            if (r2.MemberSize() >= (limit * 2))
            {
                break;
            }
            iter.Next();
        }
        if (iter.Valid())
        {
            iter.Next();
            const Data* next_field = iter.Field();
            std::string tmp;
            fill_str_reply(r1, next_field->GetDecodeString(tmp));
        }
        else
        {
            fill_str_reply(r1, "0");
        }
        return 0;
    }
Ejemplo n.º 28
0
Archivo: geo.cpp Proyecto: boreys/ardb
    int Ardb::GeoSearchByOptions(Context& ctx, ValueObject& meta, GeoSearchOptions& options)
    {
        uint64 start_time = get_current_epoch_micros();
        int ret = 0;
        double x = options.x, y = options.y;
        if (options.by_member)
        {
            Data element, score;
            element.SetString(options.member, true);
            ret = ZSetScore(ctx, meta, element, score);
            if (0 != ret || score.IsNil())
            {
                return -1;
            }
            GeoHashHelper::GetMercatorXYByHash(score.value.iv, x, y);
            //GeoHashHelper::GetXYByHash(score.value.iv, x, y);
        }
        else
        {
            if (options.coord_type != GEO_MERCATOR_TYPE)
            {
                x = GeoHashHelper::GetMercatorX(options.x);
                y = GeoHashHelper::GetMercatorY(options.y);
            }
        }
        DEBUG_LOG("####Step1: Cost %lluus", get_current_epoch_micros() - start_time);
        GeoPointArray points;
        ZSetRangeByScoreOptions fetch_options;
        fetch_options.withscores = false;
        fetch_options.op = OP_GET;
        fetch_options.fill_reply = false;
        fetch_options.fetch_geo_location = true;
        if (options.in_members)
        {
            StringSet::iterator it = options.submembers.begin();
            while (it != options.submembers.end())
            {
                Data element, score;
                element.SetString(*it, true);
                Location loc;
                ret = ZSetScore(ctx, meta, element, score, &loc);
                if (0 == ret)
                {
                    fetch_options.results.push_back(element);
                    fetch_options.locs.push_back(loc);
                }
                it++;
            }
        }
        else
        {
            GeoHashBitsSet ress;
            GeoHashHelper::GetAreasByRadiusV2(GEO_MERCATOR_TYPE, y, x, options.radius, ress);
            /*
             * Merge areas if possible to avoid disk search
             */
            std::vector<ZRangeSpec> range_array;
            GeoHashBitsSet::iterator rit = ress.begin();
            typedef TreeMap<uint64, uint64>::Type HashRangeMap;
            HashRangeMap tmp;
            while (rit != ress.end())
            {
                GeoHashBits& hash = *rit;
                GeoHashBits next = hash;
                next.bits++;
                tmp[GeoHashHelper::Allign60Bits(hash)] = GeoHashHelper::Allign60Bits(next);
                rit++;
            }
            HashRangeMap::iterator tit = tmp.begin();
            HashRangeMap::iterator nit = tmp.begin();
            nit++;
            while (tit != tmp.end())
            {
                ZRangeSpec range;
                range.contain_min = true;
                range.contain_max = true;
                range.min.SetInt64(tit->first);
                range.max.SetInt64(tit->second);
                while (nit != tmp.end() && nit->first == range.max.value.iv)
                {
                    range.max.SetInt64(nit->second);
                    nit++;
                    tit++;
                }
                range_array.push_back(range);
                nit++;
                tit++;
            }

            DEBUG_LOG("After areas merging, reduce searching area size from %u to %u", ress.size(), range_array.size());
            std::vector<ZRangeSpec>::iterator hit = range_array.begin();
            ZSetIterator* iter = NULL;
            while (hit != range_array.end())
            {
                ZRangeSpec& range = *hit;
                uint64 t1 = get_current_epoch_millis();
                ZSetRangeByScore(ctx, meta, range, fetch_options, iter);
                uint64 t2 = get_current_epoch_millis();
                DEBUG_LOG("####Cost %llums to range fetch", t2 - t1);
                hit++;
            }
            DELETE(iter);
        }
        DEBUG_LOG("####Step2: Cost %lluus", get_current_epoch_micros() - start_time);
        uint32 outrange = 0;
        LocationDeque::iterator lit = fetch_options.locs.begin();
        DataArray::iterator vit = fetch_options.results.begin();
        while (vit != fetch_options.results.end())
        {
            Location& loc = *lit;
            GeoPoint point;
            point.x = loc.x;
            point.y = loc.y;
            /*
             * distance accuracy is 0.2m
             */
            if (GeoHashHelper::GetDistanceSquareIfInRadius(GEO_MERCATOR_TYPE, x, y, point.x, point.y, options.radius,
                    point.distance, 0.2))
            {
                vit->GetDecodeString(point.value);
                /*
                 * filter by exclude/include
                 */
                if (!options.includes.empty() || !options.excludes.empty())
                {
                    Data subst;
                    subst.SetString(point.value, false);
                    bool matched = options.includes.empty() ? true : false;
                    if (!options.includes.empty())
                    {
                        StringStringMap::const_iterator sit = options.includes.begin();
                        while (sit != options.includes.end())
                        {
                            Data mv;
                            if (0 != MatchValueByPattern(ctx, sit->first, sit->second, subst, mv))
                            {
                                matched = false;
                                break;
                            }
                            else
                            {
                                matched = true;
                            }
                            sit++;
                        }
                    }
                    if (matched && !options.excludes.empty())
                    {
                        StringStringMap::const_iterator sit = options.excludes.begin();
                        while (sit != options.excludes.end())
                        {
                            Data mv;
                            if (0 == MatchValueByPattern(ctx, sit->first, sit->second, subst, mv))
                            {
                                matched = false;
                                break;
                            }
                            else
                            {
                                matched = true;
                            }
                            sit++;
                        }
                    }
                    if (matched)
                    {
                        points.push_back(point);
                    }
                }
                else
                {
                    points.push_back(point);
                }
            }
            else
            {
                outrange++;
            }
            vit++;
            lit++;
        }
        DEBUG_LOG("###Result size:%d,  outrange:%d", points.size(), outrange);
        DEBUG_LOG("####Step3: Cost %lluus", get_current_epoch_micros() - start_time);
        if (!options.nosort)
        {
            std::sort(points.begin(), points.end(), options.asc ? less_by_distance : great_by_distance);
        }
        DEBUG_LOG("####Step3.5: Cost %lluus", get_current_epoch_micros() - start_time);
        if (options.offset > 0)
        {
            if ((uint32) options.offset > points.size())
            {
                points.clear();
            }
            else
            {
                GeoPointArray::iterator start = points.begin() + options.offset;
                points.erase(points.begin(), start);
            }
        }
        if (options.limit > 0)
        {
            if ((uint32) options.limit < points.size())
            {
                GeoPointArray::iterator end = points.begin() + options.limit;
                points.erase(end, points.end());
            }
        }
        DEBUG_LOG("####Step4: Cost %lluus", get_current_epoch_micros() - start_time);
        ValueObjectMap meta_cache;
        GeoPointArray::iterator pit = points.begin();
        while (pit != points.end())
        {
            RedisReply& r = ctx.reply.AddMember();
            fill_str_reply(r, pit->value);
            GeoGetOptionArray::const_iterator ait = options.get_patterns.begin();
            while (ait != options.get_patterns.end())
            {
                if (ait->get_distances)
                {
                    RedisReply& rr = ctx.reply.AddMember();
                    rr.type = REDIS_REPLY_STRING;
                    char dbuf[128];
                    int dlen = snprintf(dbuf, sizeof(dbuf), "%.2f", sqrt(pit->distance));
                    rr.str.assign(dbuf, dlen);
                }
                else if (ait->get_coodinates)
                {
                    if (options.coord_type == GEO_WGS84_TYPE)
                    {
                        pit->x = GeoHashHelper::GetWGS84X(pit->x);
                        pit->y = GeoHashHelper::GetWGS84Y(pit->y);
                    }
                    RedisReply& rr1 = ctx.reply.AddMember();
                    RedisReply& rr2 = ctx.reply.AddMember();
                    if (options.coord_type == GEO_WGS84_TYPE)
                    {
                        fill_double_reply(rr1, pit->x);
                        fill_double_reply(rr2, pit->y);
                    }
                    else
                    {
                        char dbuf[128];
                        int dlen = snprintf(dbuf, sizeof(dbuf), "%.2f", pit->x);
                        rr1.type = REDIS_REPLY_STRING;
                        rr1.str.assign(dbuf, dlen);
                        dlen = snprintf(dbuf, sizeof(dbuf), "%.2f", pit->y);
                        rr2.type = REDIS_REPLY_STRING;
                        rr2.str.assign(dbuf, dlen);
                    }
                }
                else if (ait->hgetall)
                {
                    std::string keystr(ait->get_pattern.data(), ait->get_pattern.size());
                    string_replace(keystr, "*", pit->value);
                    RedisReply& rr = ctx.reply.AddMember();
                    rr.type = REDIS_REPLY_ARRAY;
                    HashGetAll(ctx, keystr, rr);
                }
                else
                {
                    Data v, attr;
                    v.SetString(pit->value, false);
                    GetValueByPattern(ctx, ait->get_pattern, v, attr, &meta_cache);
                    RedisReply& rr = ctx.reply.AddMember();
                    fill_value_reply(rr, attr);
                }
                ait++;
            }
            pit++;
        }
        DEBUG_LOG("####Step5: Cost %lluus", get_current_epoch_micros() - start_time);
        uint64 end_time = get_current_epoch_micros();
        DEBUG_LOG("Cost %llu microseconds to search.", end_time - start_time);
        return points.size();
    }