Beispiel #1
0
 int Ardb::HashGetAll(Context& ctx, const Slice& key, RedisReply& reply)
 {
     ValueObject meta;
     int err = GetMetaValue(ctx, key, HASH_META, meta);
     CHECK_ARDB_RETURN_VALUE(ctx.reply, err);
     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);
     reply.type = REDIS_REPLY_ARRAY;
     while (iter.Valid())
     {
         const Data* field = iter.Field();
         Data* value = iter.Value();
         RedisReply& r = reply.AddMember();
         fill_value_reply(r, *field);
         RedisReply& r1 = reply.AddMember();
         fill_value_reply(r1, *value);
         iter.Next();
     }
     return 0;
 }
Beispiel #2
0
 int Ardb::HVals(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())
     {
         Data* value = iter.Value();
         RedisReply& r = ctx.reply.AddMember();
         fill_value_reply(r, *value);
         iter.Next();
     }
     return 0;
 }
Beispiel #3
0
    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;
    }
Beispiel #4
0
    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();
    }
Beispiel #5
0
 int Ardb::LIndex(Context& ctx, RedisCommandFrame& cmd)
 {
     int64 index;
     if (!GetInt64Value(ctx, cmd.GetArguments()[1], index))
     {
         return 0;
     }
     ValueObject meta;
     int err = GetMetaValue(ctx, cmd.GetArguments()[0], LIST_META, meta);
     CHECK_ARDB_RETURN_VALUE(ctx.reply, err);
     if (0 != err)
     {
         ctx.reply.type = REDIS_REPLY_NIL;
         return 0;
     }
     if (meta.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST)
     {
         Data* entry = GetZipEntry(meta.meta.ziplist, index);
         if (NULL != entry)
         {
             fill_value_reply(ctx.reply, *entry);
         }
         else
         {
             ctx.reply.type = REDIS_REPLY_NIL;
         }
         return 0;
     }
     else
     {
         if ((index >= 0 && index >= meta.meta.Length()) || (index < 0 && (meta.meta.Length() + index) < 0))
         {
             ctx.reply.type = REDIS_REPLY_NIL;
             return 0;
         }
         ListIterator iter;
         if (meta.meta.IsSequentialList())
         {
             err = SequencialListIter(ctx, meta, iter, index);
             if (0 == err)
             {
                 if (iter.Valid())
                 {
                     fill_value_reply(ctx.reply, *(iter.Element()));
                     return 0;
                 }
             }
         }
         else
         {
             err = ListIter(ctx, meta, iter, index < 0);
             uint32 cursor = index < 0 ? 1 : 0;
             while (iter.Valid())
             {
                 if (cursor == std::abs(index))
                 {
                     fill_value_reply(ctx.reply, *(iter.Element()));
                     return 0;
                 }
                 cursor++;
                 if (index >= 0)
                 {
                     iter.Next();
                 }
                 else
                 {
                     iter.Prev();
                 }
             }
         }
         ctx.reply.type = REDIS_REPLY_NIL;
     }
     return 0;
 }
Beispiel #6
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-- && i < meta.meta.ziplist.size())
            {
                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_value_reply(r, iter.Element());
                    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_value_reply(r, iter.Element());
                    }
                    if (start < 0)
                    {
                        if (cursor < start)
                        {
                            break;
                        }
                        cursor--;
                    }
                    else
                    {
                        if (cursor > end)
                        {
                            break;
                        }
                        cursor++;
                    }
                    iter.Next();
                }
            }
        }
        return 0;
    }
Beispiel #7
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;
     }
 }