Exemplo n.º 1
0
Arquivo: geo.cpp Projeto: cvan/ardb
    /*
     *  GEOADD key MERCATOR|WGS84 x y value [x y value....]
     */
    int Ardb::GeoAdd(Context& ctx, RedisCommandFrame& cmd)
    {
        GeoAddOptions options;
        std::string err;
        if (0 != options.Parse(cmd.GetArguments(), err, 1))
        {
            fill_error_reply(ctx.reply, "%s", err.c_str());
            return 0;
        }
        GeoHashRange lat_range, lon_range;
        GeoHashHelper::GetCoordRange(options.coord_type, lat_range, lon_range);

        KeyLockerGuard keylock(m_key_lock, ctx.currentDB, cmd.GetArguments()[0]);
        ValueObject meta;
        int ret = GetMetaValue(ctx, cmd.GetArguments()[0], ZSET_META, meta);
        CHECK_ARDB_RETURN_VALUE(ctx.reply, ret);

        RedisCommandFrame zadd("zadd");
        zadd.AddArg(cmd.GetArguments()[0]);
        BatchWriteGuard guard(GetKeyValueEngine());
        GeoPointArray::iterator git = options.points.begin();
        uint32 count = 0;
        while (git != options.points.end())
        {
            GeoPoint& point = *git;
            if (point.x < lon_range.min || point.x > lon_range.max || point.y < lat_range.min
                    || point.y > lat_range.max)
            {
                guard.MarkFailed();
                break;
            }
            GeoHashBits hash;
            geohash_encode(&lat_range, &lon_range, point.y, point.x, 30, &hash);
            GeoHashFix60Bits score = hash.bits;
            Data score_value;
            score_value.SetInt64((int64) score);
            Data element;
            element.SetString(point.value, true);
            count += ZSetAdd(ctx, meta, element, score_value, NULL);

            std::string tmp;
            score_value.GetDecodeString(tmp);
            zadd.AddArg(tmp);
            element.GetDecodeString(tmp);
            zadd.AddArg(tmp);
            git++;
        }
        if (guard.Success())
        {
            SetKeyValue(ctx, meta);
            RewriteClientCommand(ctx, zadd);
            fill_int_reply(ctx.reply, count);
        }
        else
        {
            fill_error_reply(ctx.reply, "Invalid arguments");
        }
        return 0;
    }
Exemplo n.º 2
0
Arquivo: t_hash.cpp Projeto: cvan/ardb
 int Ardb::HDel(Context& ctx, RedisCommandFrame& cmd)
 {
     ValueObject meta;
     int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta);
     CHECK_ARDB_RETURN_VALUE(ctx.reply, err);
     int count = 0;
     if (err == 0)
     {
         BatchWriteGuard guard(GetKeyValueEngine());
         for (uint32 i = 1; i < cmd.GetArguments().size(); i++)
         {
             Data field(cmd.GetArguments()[i]);
             Data value;
             err = HashGet(ctx, meta, field, value);
             if (err == 0)
             {
                 if (meta.meta.encoding != COLLECTION_ECODING_ZIPMAP)
                 {
                     KeyObject k;
                     k.db = ctx.currentDB;
                     k.key = cmd.GetArguments()[0];
                     k.type = HASH_FIELD;
                     k.element = field;
                     DelKeyValue(ctx, k);
                     if (meta.meta.len > 0)
                     {
                         meta.meta.len--;
                     }
                 }
                 else
                 {
                     meta.meta.zipmap.erase(field);
                 }
                 count++;
             }
         }
         if (count > 0)
         {
             if (meta.meta.Length() != 0)
             {
                 SetKeyValue(ctx, meta);
             }
             else
             {
                 DelKeyValue(ctx, meta.key);
             }
         }
     }
     fill_int_reply(ctx.reply, count);
     return 0;
 }
Exemplo n.º 3
0
 int Ardb::LPush(Context& ctx, RedisCommandFrame& cmd)
 {
     ValueObject meta;
     int err = GetMetaValue(ctx, cmd.GetArguments()[0], LIST_META, meta);
     CHECK_ARDB_RETURN_VALUE(ctx.reply, err);
     KeyLockerGuard lock(m_key_lock, ctx.currentDB, cmd.GetArguments()[0]);
     BatchWriteGuard guard(GetKeyValueEngine(), cmd.GetArguments().size() > 2);
     for (uint32 i = 1; i < cmd.GetArguments().size(); i++)
     {
         ListInsert(ctx, meta, NULL, cmd.GetArguments()[i], true, false);
     }
     SetKeyValue(ctx, meta);
     return 0;
 }
Exemplo n.º 4
0
Arquivo: keys.cpp Projeto: boreys/ardb
 int Ardb::Del(Context& ctx, RedisCommandFrame& cmd)
 {
     if (ctx.IsSlave() && m_cfg.slave_ignore_del)
     {
         return 0;
     }
     BatchWriteGuard guard(GetKeyValueEngine());
     int count = 0;
     for (uint32 i = 0; i < cmd.GetArguments().size(); i++)
     {
         count += DeleteKey(ctx, cmd.GetArguments()[i]);
     }
     fill_int_reply(ctx.reply, count);
     return 0;
 }
Exemplo n.º 5
0
Arquivo: t_hash.cpp Projeto: cvan/ardb
 int Ardb::HClear(Context& ctx, ValueObject& meta)
 {
     BatchWriteGuard guard(GetKeyValueEngine(), meta.meta.encoding != COLLECTION_ECODING_ZIPMAP);
     if (meta.meta.encoding != COLLECTION_ECODING_ZIPMAP)
     {
         HashIterator iter;
         HashIter(ctx, meta, "", iter, false);
         while (iter.Valid())
         {
             DelRaw(ctx, iter.CurrentRawKey());
             iter.Next();
         }
     }
     DelKeyValue(ctx, meta.key);
     return 0;
 }
Exemplo n.º 6
0
 int Ardb::ListInsert(Context& ctx, const std::string& key, const std::string* match, const std::string& value,
         bool head, bool abort_nonexist)
 {
     ValueObject meta;
     int err = GetMetaValue(ctx, key, LIST_META, meta);
     CHECK_ARDB_RETURN_VALUE(ctx.reply, err);
     BatchWriteGuard guard(GetKeyValueEngine(), meta.meta.Encoding() != COLLECTION_ENCODING_ZIPLIST);
     if (0 != err && abort_nonexist)
     {
         fill_int_reply(ctx.reply, 0);
         return 0;
     }
     ListInsert(ctx, meta, match, value, head, abort_nonexist);
     SetKeyValue(ctx, meta);
     return 0;
 }
Exemplo n.º 7
0
 int Ardb::RenameList(Context& ctx, DBID srcdb, const std::string& srckey, DBID dstdb, const std::string& dstkey)
 {
     Context tmpctx;
     tmpctx.currentDB = srcdb;
     ValueObject v;
     int err = GetMetaValue(tmpctx, srckey, LIST_META, v);
     CHECK_ARDB_RETURN_VALUE(ctx.reply, err);
     if (0 != err)
     {
         fill_error_reply(ctx.reply, "no such key or some error");
         return 0;
     }
     if (v.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST)
     {
         DelKeyValue(tmpctx, v.key);
         v.key.encode_buf.Clear();
         v.key.db = dstdb;
         v.key.key = dstkey;
         v.meta.expireat = 0;
         SetKeyValue(ctx, v);
     }
     else
     {
         ListIterator iter;
         ListIter(ctx, v, iter, false);
         tmpctx.currentDB = dstdb;
         ValueObject dstmeta;
         dstmeta.key.type = KEY_META;
         dstmeta.key.key = dstkey;
         dstmeta.type = LIST_META;
         dstmeta.meta.SetFlag(COLLECTION_FLAG_SEQLIST);
         dstmeta.meta.SetEncoding(COLLECTION_ENCODING_ZIPLIST);
         BatchWriteGuard guard(GetKeyValueEngine());
         while (iter.Valid())
         {
             std::string tmpstr;
             ListInsert(tmpctx, dstmeta, NULL, iter.Element()->GetDecodeString(tmpstr), false, false);
             iter.Next();
         }
         SetKeyValue(tmpctx, dstmeta);
         tmpctx.currentDB = srcdb;
         DeleteKey(tmpctx, srckey);
     }
     ctx.data_change = true;
     return 0;
 }
Exemplo n.º 8
0
Arquivo: keys.cpp Projeto: boreys/ardb
    int Ardb::GenericExpire(Context& ctx, const Slice& key, uint64 ms)
    {
        if (ms > 0 && get_current_epoch_millis() >= ms)
        {
            return 0;
        }
        if (m_cfg.slave_ignore_expire && ctx.IsSlave())
        {
            /*
             * ignore expire setting, but issue data change event for replication
             */
            ctx.data_change = true;
            return 0;
        }

        ValueObject meta;
        int err = GetMetaValue(ctx, key, KEY_END, meta);
        if (0 != err)
        {
            return err;
        }
        BatchWriteGuard guard(GetKeyValueEngine());
        if (meta.meta.expireat != ms && meta.meta.expireat > 0)
        {
            KeyObject expire;
            expire.key = key;
            expire.type = KEY_EXPIRATION_ELEMENT;
            expire.db = ctx.currentDB;
            expire.score.SetInt64(meta.meta.expireat);
            DelKeyValue(ctx, expire);
        }
        meta.meta.expireat = ms;
        SetKeyValue(ctx, meta);

        if (meta.meta.expireat > 0)
        {
            ValueObject vv(KEY_EXPIRATION_ELEMENT);
            vv.key.key = key;
            vv.key.type = KEY_EXPIRATION_ELEMENT;
            vv.key.db = ctx.currentDB;
            vv.key.score.SetInt64(meta.meta.expireat);
            SetKeyValue(ctx, vv);
        }
        return 0;
    }
Exemplo n.º 9
0
Arquivo: t_hash.cpp Projeto: cvan/ardb
 int Ardb::RenameHash(Context& ctx, DBID srcdb, const std::string& srckey, DBID dstdb, const std::string& dstkey)
 {
     Context tmpctx;
     tmpctx.currentDB = srcdb;
     ValueObject v;
     int err = GetMetaValue(tmpctx, srckey, HASH_META, v);
     CHECK_ARDB_RETURN_VALUE(ctx.reply, err);
     if (0 != err)
     {
         fill_error_reply(ctx.reply, "no such key or some error");
         return 0;
     }
     if (v.meta.encoding == COLLECTION_ECODING_ZIPMAP)
     {
         DelKeyValue(tmpctx, v.key);
         v.key.encode_buf.Clear();
         v.key.db = dstdb;
         v.key.key = dstkey;
         v.meta.expireat = 0;
         SetKeyValue(ctx, v);
     }
     else
     {
         HashIterator iter;
         HashIter(ctx, v, "", iter, false);
         tmpctx.currentDB = dstdb;
         ValueObject dstmeta;
         dstmeta.key.type = KEY_META;
         dstmeta.key.key = dstkey;
         dstmeta.type = HASH_META;
         dstmeta.meta.encoding = COLLECTION_ECODING_ZIPMAP;
         BatchWriteGuard guard(GetKeyValueEngine());
         while (iter.Valid())
         {
             HashSet(tmpctx, dstmeta, *(iter.Field()), *(iter.Value()));
             iter.Next();
         }
         SetKeyValue(tmpctx, dstmeta);
         tmpctx.currentDB = srcdb;
         DeleteKey(tmpctx, srckey);
     }
     ctx.data_change = true;
     return 0;
 }
Exemplo n.º 10
0
 int Ardb::LClear(Context& ctx, ValueObject& meta)
 {
     BatchWriteGuard guard(GetKeyValueEngine(), meta.meta.Encoding() != COLLECTION_ENCODING_ZIPLIST);
     if (meta.meta.Encoding() != COLLECTION_ENCODING_ZIPLIST)
     {
         ListIterator iter;
         meta.meta.len = 0;
         ListIter(ctx, meta, iter, false);
         while (iter.Valid())
         {
             KeyObject fk;
             fk.db = ctx.currentDB;
             fk.key = meta.key.key;
             fk.type = LIST_ELEMENT;
             fk.score = *(iter.Score());
             DelKeyValue(ctx, fk);
             iter.Next();
         }
     }
     DelKeyValue((ctx), meta.key);
     return 0;
 }
Exemplo n.º 11
0
Arquivo: t_hash.cpp Projeto: cvan/ardb
OP_NAMESPACE_BEGIN

    int Ardb::HashMultiSet(Context& ctx, ValueObject& meta, DataMap& fs)
    {
        if (meta.meta.encoding != COLLECTION_ECODING_ZIPMAP)
        {
            bool multi_write = fs.size() > 1;
            bool set_meta = meta.meta.len != -1;

            if (meta.meta.Length() > 0)
            {
                multi_write = true;
            }
            BatchWriteGuard guard(GetKeyValueEngine(), multi_write);
            DataMap::iterator it = fs.begin();
            while (it != fs.end())
            {
                ValueObject v(HASH_FIELD);
                v.element = it->second;
                v.key.type = HASH_FIELD;
                v.key.db = meta.key.db;
                v.key.key = meta.key.key;
                v.key.element = it->first;
                SetKeyValue(ctx, v);
                it++;
            }
            if (set_meta)
            {
                meta.meta.len = -1;
                SetKeyValue(ctx, meta);
            }
            fill_int_reply(ctx.reply, fs.size());
        }
        else
        {
            int64 oldlen = meta.meta.Length();
            DataMap::iterator it = fs.begin();
            bool zipsave = true;
            while (it != fs.end())
            {
                const Data& field = it->first;
                Data& value = it->second;
                meta.meta.zipmap[field] = value;
                it++;
                if (!meta.attach.force_zipsave
                        && (field.StringLength() > m_cfg.hash_max_ziplist_value
                                || value.StringLength() > m_cfg.hash_max_ziplist_value))
                {
                    zipsave = false;
                }
            }
            if (meta.meta.zipmap.size() > m_cfg.hash_max_ziplist_entries)
            {
                zipsave = false;
            }
            BatchWriteGuard guard(GetKeyValueEngine(), !zipsave);
            if (!zipsave)
            {
                /*
                 * convert to non zipmap encoding
                 */
                DataMap::iterator fit = meta.meta.zipmap.begin();
                while (fit != meta.meta.zipmap.end())
                {
                    ValueObject v(HASH_FIELD);
                    v.element = fit->second;
                    v.key.type = HASH_FIELD;
                    v.key.db = meta.key.db;
                    v.key.key = meta.key.key;
                    v.key.element = fit->first;
                    SetKeyValue(ctx, v);
                    fit++;
                }
                meta.meta.len = meta.meta.zipmap.size();
                meta.meta.zipmap.clear();
                meta.meta.encoding = COLLECTION_ECODING_RAW;
            }
            SetKeyValue(ctx, meta);
            fill_int_reply(ctx.reply, meta.meta.Length() - oldlen);
        }

        return 0;
    }
Exemplo n.º 12
0
    int Ardb::LTrim(Context& ctx, RedisCommandFrame& cmd)
    {
        int64 start, end;
        if (!GetInt64Value(ctx, cmd.GetArguments()[1], start) || !GetInt64Value(ctx, cmd.GetArguments()[2], end))
        {
            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_status_reply(ctx.reply, "OK");
            return 0;
        }
        /* convert negative indexes */
        if (start < 0)
            start = meta.meta.Length() + start;
        if (end < 0)
            end = meta.meta.Length() + end;
        if (start < 0)
            start = 0;
        if (end >= meta.meta.Length())
            end = meta.meta.Length() - 1;

        /* Invariant: start >= 0, so this test will be true when end < 0.
         * The range is empty when start > end or start >= length. */
        if (start > end || start >= meta.meta.Length())
        {
            /* Out of range start or start > end result in empty list */
            DeleteKey(ctx, cmd.GetArguments()[0]);
            return 0;
        }
        if (meta.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST)
        {
            DataArray newzip;
            for (int64 i = start; i <= end; i++)
            {
                newzip.push_back(meta.meta.ziplist[i]);
            }
            meta.meta.ziplist = newzip;
            SetKeyValue(ctx, meta);
        }
        else
        {
            BatchWriteGuard guard(GetKeyValueEngine());
            if (meta.meta.IsSequentialList())
            {
                int64 listlen = meta.meta.Length();
                for (int64 s = 0; s < listlen; s++)
                {
                    if (s == start)
                    {
                        s = end;
                        continue;
                    }
                    KeyObject lk;
                    lk.db = meta.key.db;
                    lk.key = meta.key.key;
                    lk.type = LIST_ELEMENT;
                    lk.score = meta.meta.min_index.IncrBy(s);
                    meta.meta.len--;
                    DelKeyValue(ctx, lk);
                }
                meta.meta.max_index = meta.meta.min_index;
                meta.meta.min_index.IncrBy(start);
                meta.meta.max_index.IncrBy(end);
            }
            else
            {
                ListIterator iter;
                ListIter(ctx, meta, iter, false);
                int64 cursor = 0;
                while (iter.Valid())
                {
                    if (cursor < start || cursor > end)
                    {
                        DelRaw(ctx, iter.CurrentRawKey());
                        meta.meta.len--;
                    }
                    if (cursor == start)
                    {
                        meta.meta.min_index = *(iter.Element());
                    }
                    else if (cursor == end)
                    {
                        meta.meta.max_index = *(iter.Element());
                    }
                    cursor++;
                    iter.Next();
                }
            }
            SetKeyValue(ctx, meta);
        }
        return 0;
    }
Exemplo n.º 13
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;
 }
Exemplo n.º 14
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;
     }
 }
Exemplo n.º 15
0
    int Ardb::SortCommand(Context& ctx, const Slice& key, SortOptions& options, DataArray& values)
    {
        values.clear();

        KeyType keytype = KEY_END;
        GetType(ctx, key, keytype);

        switch (keytype)
        {
            case LIST_META:
            {
                ListRange(ctx, key, 0, -1);
                break;
            }
            case SET_META:
            {
                SetMembers(ctx, key);
                break;
            }
            case ZSET_META:
            {
                ZSetRange(ctx, key, 0, -1, false, false, OP_GET);
                if (NULL == options.by)
                {
                    options.nosort = true;
                }
                break;
            }
            default:
            {
                return ERR_INVALID_TYPE;
            }
        }
        DataArray sortvals;
        if (ctx.reply.MemberSize() > 0)
        {
            for (uint32 i = 0; i < ctx.reply.MemberSize(); i++)
            {
                Data v;
                v.SetString(ctx.reply.MemberAt(i).str, true);
                sortvals.push_back(v);
            }
        }
        if (sortvals.empty())
        {
            return 0;
        }
        if (options.with_limit)
        {
            if (options.limit_offset < 0)
            {
                options.limit_offset = 0;
            }
            if ((uint32) options.limit_offset > sortvals.size())
            {
                values.clear();
                return 0;
            }
            if (options.limit_count < 0)
            {
                options.limit_count = sortvals.size();
            }
        }

        std::vector<SortValue> sortvec;
        if (!options.nosort)
        {
            if (NULL != options.by)
            {
                sortvec.reserve(sortvals.size());
            }
            for (uint32 i = 0; i < sortvals.size(); i++)
            {
                if (NULL != options.by)
                {
                    sortvec.push_back(SortValue(&sortvals[i]));
                    if (GetValueByPattern(ctx, options.by, sortvals[i], sortvec[i].cmp) < 0)
                    {
                        DEBUG_LOG("Failed to get value by pattern:%s", options.by);
                        sortvec[i].cmp.Clear();
                        continue;
                    }
                }
                if (options.with_alpha)
                {
                    if (NULL != options.by)
                    {
                        sortvec[i].cmp.ToString();
                    }
                    else
                    {
                        sortvals[i].ToString();
                    }
                }
            }
            if (NULL != options.by)
            {
                if (!options.is_desc)
                {
                    std::sort(sortvec.begin(), sortvec.end(), less_value<SortValue>);
                }
                else
                {
                    std::sort(sortvec.begin(), sortvec.end(), greater_value<SortValue>);
                }

            }
            else
            {
                if (!options.is_desc)
                {
                    std::sort(sortvals.begin(), sortvals.end(), less_value<Data>);
                }
                else
                {
                    std::sort(sortvals.begin(), sortvals.end(), greater_value<Data>);
                }
            }
        }

        if (!options.with_limit)
        {
            options.limit_offset = 0;
            options.limit_count = sortvals.size();
        }

        uint32 count = 0;
        for (uint32 i = options.limit_offset; i < sortvals.size() && count < (uint32) options.limit_count; i++, count++)
        {
            Data* patternObj = NULL;
            if (NULL != options.by)
            {
                patternObj = sortvec[i].value;
            }
            else
            {
                patternObj = &(sortvals[i]);
            }
            if (options.get_patterns.empty())
            {
                values.push_back(*patternObj);
            }
            else
            {
                for (uint32 j = 0; j < options.get_patterns.size(); j++)
                {
                    Data vo;
                    if (GetValueByPattern(ctx, options.get_patterns[j], *patternObj, vo) < 0)
                    {
                        DEBUG_LOG("Failed to get value by pattern for:%s", options.get_patterns[j]);
                        vo.Clear();
                    }
                    values.push_back(vo);
                }
            }
        }

        uint32 step = options.get_patterns.empty() ? 1 : options.get_patterns.size();
        switch (options.aggregate)
        {
            case AGGREGATE_SUM:
            case AGGREGATE_AVG:
            {
                DataArray result;
                result.resize(step);

                for (uint32 i = 0; i < result.size(); i++)
                {
                    for (uint32 j = i; j < values.size(); j += step)
                    {
                        result[i].IncrBy(values[j]);
                    }
                }
                if (options.aggregate == AGGREGATE_AVG)
                {
                    size_t count = values.size() / step;
                    for (uint32 i = 0; i < result.size(); i++)
                    {
                        result[i].SetDouble(result[i].NumberValue() / count);
                    }
                }
                values.assign(result.begin(), result.end());
                break;
            }
            case AGGREGATE_MAX:
            case AGGREGATE_MIN:
            {
                DataArray result;
                result.resize(step);
                for (uint32 i = 0; i < result.size(); i++)
                {
                    for (uint32 j = i; j < values.size(); j += step)
                    {
                        if (result[i].IsNil())
                        {
                            result[i] = values[j];
                        }
                        else
                        {
                            if (options.aggregate == AGGREGATE_MIN)
                            {
                                if (values[j] < result[i])
                                {
                                    result[i] = values[j];
                                }
                            }
                            else
                            {
                                if (values[j] > result[i])
                                {
                                    result[i] = values[j];
                                }
                            }
                        }
                    }
                }
                values.assign(result.begin(), result.end());
                break;
            }
            case AGGREGATE_COUNT:
            {
                size_t size = values.size() / step;
                values.clear();
                Data v;
                v.SetInt64(size);
                values.push_back(v);
                break;
            }
            default:
            {
                break;
            }
        }

        if (options.store_dst != NULL && !values.empty())
        {
            DeleteKey(ctx, options.store_dst);

            ValueObject list_meta;
            list_meta.key.key = options.store_dst;
            list_meta.key.type = KEY_META;
            list_meta.key.db = ctx.currentDB;
            list_meta.type = LIST_META;
            list_meta.meta.SetEncoding(COLLECTION_ECODING_ZIPLIST);

            BatchWriteGuard guard(GetKeyValueEngine());
            DataArray::iterator it = values.begin();
            while (it != values.end())
            {
                if (!it->IsNil())
                {
                    std::string tmp;
                    it->GetDecodeString(tmp);
                    ListInsert(ctx, list_meta, NULL, tmp, false, false);
                }
                it++;
            }
            SetKeyValue(ctx, list_meta);
        }
        return 0;
    }