From 91ba4d2d25d2c6200e22e92e9c662fb093b5979e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BA=AA=E5=8D=8E=E8=A3=95?= <8042833@qq.com> Date: Wed, 31 May 2023 11:51:12 +0000 Subject: [PATCH 01/11] tmp update --- src/commands/cmd_zset.cc | 122 +++++++++++++++++++++++ tests/gocase/unit/type/zset/zset_test.go | 19 ++++ 2 files changed, 141 insertions(+) diff --git a/src/commands/cmd_zset.cc b/src/commands/cmd_zset.cc index 89ab826bb43..a9c0653c543 100644 --- a/src/commands/cmd_zset.cc +++ b/src/commands/cmd_zset.cc @@ -337,6 +337,127 @@ class CommandZMPop : public Commander { int count_ = 1; }; + +class CommandZRangeStore : public Commander { + public: + explicit CommandZRangeStore() + :range_type_(kZRangeRank) ,direction_(kZRangeDirectionForward) {} + + Status Parse(const std::vector &args) override { + dst_ = args[1]; + src_ = args[2]; + + int64_t offset = 0; + int64_t count = -1; + // skip the args and parse remaining optional arguments + CommandParser parser(args, 5); + while (parser.Good()) { + if (parser.EatEqICase("limit")) { + auto parse_offset = parser.TakeInt(); + auto parse_count = parser.TakeInt(); + if (!parse_offset || !parse_count) { + return {Status::RedisParseErr, errValueNotInteger}; + } + offset = *parse_offset; + count = *parse_count; + } else if (parser.EatEqICase("bylex")) { + range_type_ = kZRangeLex; + } else if (parser.EatEqICase("byscore")) { + range_type_ = kZRangeScore; + } else if (parser.EatEqICase("rev")) { + direction_ = kZRangeDirectionReverse; + } else { + return parser.InvalidSyntax(); + } + } + + if (count != -1 && range_type_ == kZRangeRank) { + return {Status::RedisParseErr, + "syntax error, LIMIT is only supported in combination with either BYSCORE or BYLEX"}; + } + + // resolve index of + int min_idx = 3; + int max_idx = 4; + if (direction_ == kZRangeDirectionReverse && (range_type_ == kZRangeLex || range_type_ == kZRangeScore)) { + min_idx = 4; + max_idx = 3; + } + + // parse range spec + switch (range_type_) { + case kZRangeAuto: + case kZRangeRank: + GET_OR_RET(ParseRangeRankSpec(args[min_idx], args[max_idx], &rank_spec_)); + if (direction_ == kZRangeDirectionReverse) { + rank_spec_.reversed = true; + } + break; + case kZRangeLex: + GET_OR_RET(ParseRangeLexSpec(args[min_idx], args[max_idx], &lex_spec_)); + lex_spec_.offset = offset; + lex_spec_.count = count; + if (direction_ == kZRangeDirectionReverse) { + lex_spec_.reversed = true; + } + break; + case kZRangeScore: + GET_OR_RET(ParseRangeScoreSpec(args[min_idx], args[max_idx], &score_spec_)); + score_spec_.offset = offset; + score_spec_.count = count; + if (direction_ == kZRangeDirectionReverse) { + score_spec_.reversed = true; + } + break; + } + + return Status::OK(); + } + + Status Execute(Server *svr, Connection *conn, std::string *output) override { + redis::ZSet zset_db(svr->storage, conn->GetNamespace()); + + std::vector member_scores; + std::vector members; + + rocksdb::Status s; + switch (range_type_) { + case kZRangeAuto: + case kZRangeRank: + s = zset_db.RangeByRank(src_, rank_spec_, &member_scores, nullptr); + break; + case kZRangeScore: + s = zset_db.RangeByScore(src_, score_spec_, &member_scores, nullptr); + break; + case kZRangeLex: + s = zset_db.RangeByLex(src_, lex_spec_, &members, nullptr); + break; + } + if (!s.ok()) { + return {Status::RedisExecErr, s.ToString()}; + } + uint64_t ret = 0; + s = zset_db.Add(dst_,ZAddFlags(),&member_scores,&ret); + if (!s.ok()) { + return {Status::RedisExecErr, s.ToString()}; + } + *output = redis::Integer(ret); + return Status::OK(); + + } + + private: + std::string src_; + std::string dst_; + ZRangeType range_type_; + ZRangeDirection direction_; + + RangeRankSpec rank_spec_; + RangeLexSpec lex_spec_; + RangeScoreSpec score_spec_; +}; + + class CommandZRangeGeneric : public Commander { public: explicit CommandZRangeGeneric(ZRangeType range_type = kZRangeAuto, ZRangeDirection direction = kZRangeDirectionAuto) @@ -817,6 +938,7 @@ REDIS_REGISTER_COMMANDS(MakeCmdAttr("zadd", -4, "write", 1, 1, 1), MakeCmdAttr("zpopmax", -2, "write", 1, 1, 1), MakeCmdAttr("zpopmin", -2, "write", 1, 1, 1), MakeCmdAttr("zmpop", -4, "write", CommandZMPop::Range), + MakeCmdAttr("zrangestore", -4, "write", 1, 1, 1), MakeCmdAttr("zrange", -4, "read-only", 1, 1, 1), MakeCmdAttr("zrevrange", -4, "read-only", 1, 1, 1), MakeCmdAttr("zrangebylex", -4, "read-only", 1, 1, 1), diff --git a/tests/gocase/unit/type/zset/zset_test.go b/tests/gocase/unit/type/zset/zset_test.go index cd98d3cd09a..1d4fc74c56a 100644 --- a/tests/gocase/unit/type/zset/zset_test.go +++ b/tests/gocase/unit/type/zset/zset_test.go @@ -337,6 +337,25 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s require.EqualValues(t, 0, rdb.Exists(ctx, "zseta", "zsetb").Val()) }) + t.Run(fmt.Sprintf("ZRANGESTORE basics - %s", encoding), func(t *testing.T) { + rdb.Del(ctx, "zsrc") + rdb.Del(ctx, "zdst") + + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 1, Member: "a"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 2, Member: "b"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 3, Member: "c"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 4, Member: "d"}) + rdb.ZRangeStore(ctx,"zdst",redis.ZRangeArgs{ + Key: "zsrc", + Start: 1, + Stop: 3, + }); + require.Equal(t, []string{"a", "b", "c", "d"}, rdb.ZRange(ctx, "ztmp", 0, -1).Val()) + require.Equal(t, []string{"a", "b", "c"}, rdb.ZRange(ctx, "ztmp", 0, -2).Val()) + require.Equal(t, []string{"b", "c", "d"}, rdb.ZRange(ctx, "ztmp", 1, -1).Val()) + }) + + t.Run(fmt.Sprintf("ZRANGE basics - %s", encoding), func(t *testing.T) { rdb.Del(ctx, "ztmp") rdb.ZAdd(ctx, "ztmp", redis.Z{Score: 1, Member: "a"}) From 6ae551b8b2e7705489d2ff55fee13faa5fa6f585 Mon Sep 17 00:00:00 2001 From: jihuayu <8042833@qq.com> Date: Wed, 31 May 2023 22:37:29 +0800 Subject: [PATCH 02/11] format the code --- src/commands/cmd_zset.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/commands/cmd_zset.cc b/src/commands/cmd_zset.cc index a9c0653c543..a3aa7fd198b 100644 --- a/src/commands/cmd_zset.cc +++ b/src/commands/cmd_zset.cc @@ -337,11 +337,9 @@ class CommandZMPop : public Commander { int count_ = 1; }; - class CommandZRangeStore : public Commander { public: - explicit CommandZRangeStore() - :range_type_(kZRangeRank) ,direction_(kZRangeDirectionForward) {} + explicit CommandZRangeStore() : range_type_(kZRangeRank), direction_(kZRangeDirectionForward) {} Status Parse(const std::vector &args) override { dst_ = args[1]; @@ -437,13 +435,12 @@ class CommandZRangeStore : public Commander { return {Status::RedisExecErr, s.ToString()}; } uint64_t ret = 0; - s = zset_db.Add(dst_,ZAddFlags(),&member_scores,&ret); + s = zset_db.Add(dst_, ZAddFlags(), &member_scores, &ret); if (!s.ok()) { return {Status::RedisExecErr, s.ToString()}; } *output = redis::Integer(ret); return Status::OK(); - } private: @@ -457,7 +454,6 @@ class CommandZRangeStore : public Commander { RangeScoreSpec score_spec_; }; - class CommandZRangeGeneric : public Commander { public: explicit CommandZRangeGeneric(ZRangeType range_type = kZRangeAuto, ZRangeDirection direction = kZRangeDirectionAuto) From c28ec4a93f2a210b7f3a91f220811cd00cd93c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BA=AA=E5=8D=8E=E8=A3=95?= <8042833@qq.com> Date: Thu, 1 Jun 2023 02:39:44 +0000 Subject: [PATCH 03/11] update test --- tests/gocase/unit/type/zset/zset_test.go | 39 ++++++++++++++++++------ 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/tests/gocase/unit/type/zset/zset_test.go b/tests/gocase/unit/type/zset/zset_test.go index 1d4fc74c56a..890c3750b99 100644 --- a/tests/gocase/unit/type/zset/zset_test.go +++ b/tests/gocase/unit/type/zset/zset_test.go @@ -345,16 +345,37 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 2, Member: "b"}) rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 3, Member: "c"}) rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 4, Member: "d"}) - rdb.ZRangeStore(ctx,"zdst",redis.ZRangeArgs{ - Key: "zsrc", - Start: 1, - Stop: 3, - }); - require.Equal(t, []string{"a", "b", "c", "d"}, rdb.ZRange(ctx, "ztmp", 0, -1).Val()) - require.Equal(t, []string{"a", "b", "c"}, rdb.ZRange(ctx, "ztmp", 0, -2).Val()) - require.Equal(t, []string{"b", "c", "d"}, rdb.ZRange(ctx, "ztmp", 1, -1).Val()) - }) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ + Key: "zsrc", + Start: 1, + Stop: 3, + }) + require.Equal(t, []string{"b", "c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ + Key: "zsrc", + Start: 0, + Stop: 2, + }) + require.Equal(t, []string{"a", "b", "c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + rdb.Del(ctx, "zdst") + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ + Key: "zsrc", + Start: 0, + Stop: 0, + }) + require.Equal(t, []string{"a"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + + rdb.Del(ctx, "zdst") + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ + Key: "zsrc", + Start: 99, + Stop: 99, + }) + require.Equal(t, []string{}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + + }) t.Run(fmt.Sprintf("ZRANGE basics - %s", encoding), func(t *testing.T) { rdb.Del(ctx, "ztmp") From 32f6ebebd90aea5fc5ed04dda9cb5490d63f81ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BA=AA=E5=8D=8E=E8=A3=95?= <8042833@qq.com> Date: Thu, 1 Jun 2023 05:49:20 +0000 Subject: [PATCH 04/11] add test case --- tests/gocase/unit/type/zset/zset_test.go | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/gocase/unit/type/zset/zset_test.go b/tests/gocase/unit/type/zset/zset_test.go index 890c3750b99..4e2afb882ad 100644 --- a/tests/gocase/unit/type/zset/zset_test.go +++ b/tests/gocase/unit/type/zset/zset_test.go @@ -375,6 +375,50 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s }) require.Equal(t, []string{}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + rdb.Del(ctx, "zdst") + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ + Key: "zsrc", + Start: 2, + Stop: 5, + ByScore: true, + }) + require.Equal(t, []string{"b", "c"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + + rdb.Del(ctx, "zdst") + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ + Key: "zsrc", + Start: 2, + Stop: 3, + ByScore: true, + }) + require.Equal(t, []string{"b"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + + rdb.Del(ctx, "zdst") + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ + Key: "zsrc", + Start: "[c", + Stop: "[f", + ByScore: true, + }) + require.Equal(t, []string{"c", "d", "f"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + + rdb.Del(ctx, "zdst") + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ + Key: "zsrc", + Start: "[c", + Stop: "(f", + ByLex: true, + }) + require.Equal(t, []string{"c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + + rdb.Del(ctx, "zdst") + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ + Key: "zsrc", + Start: "-", + Stop: "(f", + ByLex: true, + }) + require.Equal(t, []string{"a", "b", "c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) }) t.Run(fmt.Sprintf("ZRANGE basics - %s", encoding), func(t *testing.T) { From 08bbdf91c8283aecc8fcb7dba1414e3440720116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BA=AA=E5=8D=8E=E8=A3=95?= <8042833@qq.com> Date: Thu, 1 Jun 2023 05:52:54 +0000 Subject: [PATCH 05/11] format code --- tests/gocase/unit/type/zset/zset_test.go | 60 ++++-------------------- 1 file changed, 10 insertions(+), 50 deletions(-) diff --git a/tests/gocase/unit/type/zset/zset_test.go b/tests/gocase/unit/type/zset/zset_test.go index 4e2afb882ad..bb1ac4180ee 100644 --- a/tests/gocase/unit/type/zset/zset_test.go +++ b/tests/gocase/unit/type/zset/zset_test.go @@ -345,79 +345,39 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 2, Member: "b"}) rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 3, Member: "c"}) rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 4, Member: "d"}) - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ - Key: "zsrc", - Start: 1, - Stop: 3, - }) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: 3}) require.Equal(t, []string{"b", "c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ - Key: "zsrc", - Start: 0, - Stop: 2, - }) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 0, Stop: 2}) require.Equal(t, []string{"a", "b", "c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ - Key: "zsrc", - Start: 0, - Stop: 0, - }) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 0, Stop: 0}) require.Equal(t, []string{"a"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ - Key: "zsrc", - Start: 99, - Stop: 99, - }) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 99, Stop: 99}) require.Equal(t, []string{}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ - Key: "zsrc", - Start: 2, - Stop: 5, - ByScore: true, - }) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 2, Stop: 5, ByScore: true}) require.Equal(t, []string{"b", "c"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ - Key: "zsrc", - Start: 2, - Stop: 3, - ByScore: true, - }) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 2, + Stop: 3, ByScore: true}) require.Equal(t, []string{"b"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ - Key: "zsrc", - Start: "[c", - Stop: "[f", - ByScore: true, - }) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "[c", Stop: "[f", ByScore: true}) require.Equal(t, []string{"c", "d", "f"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ - Key: "zsrc", - Start: "[c", - Stop: "(f", - ByLex: true, - }) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "[c", Stop: "(f", ByLex: true}) require.Equal(t, []string{"c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{ - Key: "zsrc", - Start: "-", - Stop: "(f", - ByLex: true, - }) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "-", Stop: "(f", ByLex: true}) require.Equal(t, []string{"a", "b", "c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) }) From 1dc0ef911e596f2cf31cfce4cd2ea051e5ce651e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BA=AA=E5=8D=8E=E8=A3=95?= <8042833@qq.com> Date: Thu, 1 Jun 2023 06:00:22 +0000 Subject: [PATCH 06/11] add count limit and rev test --- tests/gocase/unit/type/zset/zset_test.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/gocase/unit/type/zset/zset_test.go b/tests/gocase/unit/type/zset/zset_test.go index bb1ac4180ee..13777b85e6b 100644 --- a/tests/gocase/unit/type/zset/zset_test.go +++ b/tests/gocase/unit/type/zset/zset_test.go @@ -359,17 +359,28 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 99, Stop: 99}) require.Equal(t, []string{}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + // count limit + rdb.Del(ctx, "zdst") + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: -1, Count: 3}) + require.Equal(t, []string{"b", "c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + + // rev + rdb.Del(ctx, "zdst") + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: 3, Rev: true}) + require.Equal(t, []string{"d", "c", "b"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + + // byScore rdb.Del(ctx, "zdst") rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 2, Stop: 5, ByScore: true}) require.Equal(t, []string{"b", "c"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 2, - Stop: 3, ByScore: true}) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 2, Stop: 3, ByScore: true}) require.Equal(t, []string{"b"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + // byLex rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "[c", Stop: "[f", ByScore: true}) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "[c", Stop: "[f", ByLex: true}) require.Equal(t, []string{"c", "d", "f"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) rdb.Del(ctx, "zdst") From 32283e6428028bf65675e67b97bc956152b01a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BA=AA=E5=8D=8E=E8=A3=95?= <8042833@qq.com> Date: Thu, 1 Jun 2023 06:09:27 +0000 Subject: [PATCH 07/11] update test --- tests/gocase/unit/type/zset/zset_test.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/gocase/unit/type/zset/zset_test.go b/tests/gocase/unit/type/zset/zset_test.go index 13777b85e6b..0c291f56cba 100644 --- a/tests/gocase/unit/type/zset/zset_test.go +++ b/tests/gocase/unit/type/zset/zset_test.go @@ -342,9 +342,12 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s rdb.Del(ctx, "zdst") rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 1, Member: "a"}) - rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 2, Member: "b"}) - rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 3, Member: "c"}) - rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 4, Member: "d"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 3, Member: "b"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 4, Member: "c"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 6, Member: "d"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 9, Member: "g"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 7, Member: "f"}) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: 3}) require.Equal(t, []string{"b", "c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) @@ -359,11 +362,6 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 99, Stop: 99}) require.Equal(t, []string{}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) - // count limit - rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: -1, Count: 3}) - require.Equal(t, []string{"b", "c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) - // rev rdb.Del(ctx, "zdst") rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: 3, Rev: true}) @@ -390,6 +388,11 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s rdb.Del(ctx, "zdst") rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "-", Stop: "(f", ByLex: true}) require.Equal(t, []string{"a", "b", "c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + + // limit offset count + rdb.Del(ctx, "zdst") + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "[a", Stop: "[g", ByLex: true, Offset: 2, Count: 3}) + require.Equal(t, []string{"c", "d", "f"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) }) t.Run(fmt.Sprintf("ZRANGE basics - %s", encoding), func(t *testing.T) { From 2d22d6fd4d87ce071d90fc33ac88a90f56d2f982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BA=AA=E5=8D=8E=E8=A3=95?= <8042833@qq.com> Date: Thu, 1 Jun 2023 07:35:55 +0000 Subject: [PATCH 08/11] update test --- tests/gocase/unit/type/zset/zset_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gocase/unit/type/zset/zset_test.go b/tests/gocase/unit/type/zset/zset_test.go index 0c291f56cba..9e37073fb84 100644 --- a/tests/gocase/unit/type/zset/zset_test.go +++ b/tests/gocase/unit/type/zset/zset_test.go @@ -365,7 +365,7 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s // rev rdb.Del(ctx, "zdst") rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: 3, Rev: true}) - require.Equal(t, []string{"d", "c", "b"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + require.Equal(t, []string{"c", "d", "f"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) // byScore rdb.Del(ctx, "zdst") From 0594e3abc7ed8b69cedfc8b6953a702e09965428 Mon Sep 17 00:00:00 2001 From: jihuayu <8042833@qq.com> Date: Fri, 2 Jun 2023 21:33:16 +0800 Subject: [PATCH 09/11] update tests --- tests/gocase/unit/type/zset/zset_test.go | 32 ++++++++++++++++-------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/tests/gocase/unit/type/zset/zset_test.go b/tests/gocase/unit/type/zset/zset_test.go index 9e37073fb84..3a6a2f95b33 100644 --- a/tests/gocase/unit/type/zset/zset_test.go +++ b/tests/gocase/unit/type/zset/zset_test.go @@ -358,6 +358,7 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 0, Stop: 0}) require.Equal(t, []string{"a"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + //add none rdb.Del(ctx, "zdst") rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 99, Stop: 99}) require.Equal(t, []string{}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) @@ -372,27 +373,38 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 2, Stop: 5, ByScore: true}) require.Equal(t, []string{"b", "c"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + // byScore limit offset count rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 2, Stop: 3, ByScore: true}) - require.Equal(t, []string{"b"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "1", Stop: "7", ByScore: true, Offset: 2, Count: 3}) + require.Equal(t, []string{"c", "d", "f"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) // byLex rdb.Del(ctx, "zdst") rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "[c", Stop: "[f", ByLex: true}) require.Equal(t, []string{"c", "d", "f"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + // byLex limit offset count rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "[c", Stop: "(f", ByLex: true}) - require.Equal(t, []string{"c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "[a", Stop: "[g", ByLex: true, Offset: 2, Count: 3}) + require.Equal(t, []string{"c", "d", "f"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + }) + t.Run(fmt.Sprintf("ZRANGESTORE error - %s", encoding), func(t *testing.T) { + rdb.Del(ctx, "zsrc") rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "-", Stop: "(f", ByLex: true}) - require.Equal(t, []string{"a", "b", "c", "d"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) - // limit offset count - rdb.Del(ctx, "zdst") - rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "[a", Stop: "[g", ByLex: true, Offset: 2, Count: 3}) - require.Equal(t, []string{"c", "d", "f"}, rdb.ZRange(ctx, "zdst", 0, -1).Val()) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 1, Member: "a"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 3, Member: "b"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 4, Member: "c"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 6, Member: "d"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 9, Member: "g"}) + rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 7, Member: "f"}) + + util.ErrorRegexp(t, rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "xx", Stop: "ww"}).Err(), ".*not an integer.*") + util.ErrorRegexp(t, rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1}).Err(), ".*double.*") + util.ErrorRegexp(t, rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: 3, Count: 1, Offset: 1}).Err(), ".*error.*") + util.ErrorRegexp(t, rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: 3, Rev: true}).Err(), ".*double.*") + util.ErrorRegexp(t, rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: 3, ByScore: true, ByLex: true}).Err(), ".*double.*") }) t.Run(fmt.Sprintf("ZRANGE basics - %s", encoding), func(t *testing.T) { From b7f43f3024f11fce0439817ead3e6651500ad350 Mon Sep 17 00:00:00 2001 From: jihuayu <8042833@qq.com> Date: Sat, 3 Jun 2023 18:39:12 +0800 Subject: [PATCH 10/11] update RangeByLex function --- src/commands/cmd_zset.cc | 27 ++++++------------ src/types/redis_zset.cc | 8 +++--- src/types/redis_zset.h | 3 +- tests/cppunit/types/zset_test.cc | 49 ++++++++++++++++++-------------- 4 files changed, 41 insertions(+), 46 deletions(-) diff --git a/src/commands/cmd_zset.cc b/src/commands/cmd_zset.cc index a3aa7fd198b..216288fdcb9 100644 --- a/src/commands/cmd_zset.cc +++ b/src/commands/cmd_zset.cc @@ -416,7 +416,6 @@ class CommandZRangeStore : public Commander { redis::ZSet zset_db(svr->storage, conn->GetNamespace()); std::vector member_scores; - std::vector members; rocksdb::Status s; switch (range_type_) { @@ -428,12 +427,13 @@ class CommandZRangeStore : public Commander { s = zset_db.RangeByScore(src_, score_spec_, &member_scores, nullptr); break; case kZRangeLex: - s = zset_db.RangeByLex(src_, lex_spec_, &members, nullptr); + s = zset_db.RangeByLex(src_, lex_spec_, &member_scores, nullptr); break; } if (!s.ok()) { return {Status::RedisExecErr, s.ToString()}; } + uint64_t ret = 0; s = zset_db.Add(dst_, ZAddFlags(), &member_scores, &ret); if (!s.ok()) { @@ -547,7 +547,6 @@ class CommandZRangeGeneric : public Commander { redis::ZSet zset_db(svr->storage, conn->GetNamespace()); std::vector member_scores; - std::vector members; rocksdb::Status s; switch (range_type_) { @@ -559,29 +558,19 @@ class CommandZRangeGeneric : public Commander { s = zset_db.RangeByScore(key_, score_spec_, &member_scores, nullptr); break; case kZRangeLex: - s = zset_db.RangeByLex(key_, lex_spec_, &members, nullptr); + s = zset_db.RangeByLex(key_, lex_spec_, &member_scores, nullptr); break; } if (!s.ok()) { return {Status::RedisExecErr, s.ToString()}; } - switch (range_type_) { - case kZRangeLex: - output->append(redis::MultiBulkString(members, false)); - return Status::OK(); - case kZRangeAuto: - case kZRangeRank: - case kZRangeScore: - output->append(redis::MultiLen(member_scores.size() * (with_scores_ ? 2 : 1))); - for (const auto &ms : member_scores) { - output->append(redis::BulkString(ms.member)); - if (with_scores_) output->append(redis::BulkString(util::Float2String(ms.score))); - } - return Status::OK(); + output->append(redis::MultiLen(member_scores.size() * (with_scores_ ? 2 : 1))); + for (const auto &ms : member_scores) { + output->append(redis::BulkString(ms.member)); + if (with_scores_) output->append(redis::BulkString(util::Float2String(ms.score))); } - - return {Status::RedisParseErr, "unexpected range type"}; + return Status::OK(); } private: diff --git a/src/types/redis_zset.cc b/src/types/redis_zset.cc index a9b1ba24f0a..dbe65aa6390 100644 --- a/src/types/redis_zset.cc +++ b/src/types/redis_zset.cc @@ -421,9 +421,9 @@ rocksdb::Status ZSet::RangeByScore(const Slice &user_key, const RangeScoreSpec & return rocksdb::Status::OK(); } -rocksdb::Status ZSet::RangeByLex(const Slice &user_key, const RangeLexSpec &spec, Members *members, +rocksdb::Status ZSet::RangeByLex(const Slice &user_key, const RangeLexSpec &spec, MemberScores *mscores, uint64_t *removed_cnt) { - if (members) members->clear(); + if (mscores) mscores->clear(); uint64_t cnt = 0; if (!removed_cnt) removed_cnt = &cnt; @@ -498,10 +498,10 @@ rocksdb::Status ZSet::RangeByLex(const Slice &user_key, const RangeLexSpec &spec batch->Delete(score_cf_handle_, score_key); batch->Delete(iter->key()); } else { - if (members) members->emplace_back(member.ToString()); + if (mscores) mscores->emplace_back(MemberScore{member.ToString(), DecodeDouble(iter->value().data())}); } *removed_cnt += 1; - if (spec.count > 0 && members && members->size() >= static_cast(spec.count)) break; + if (spec.count > 0 && mscores && mscores->size() >= static_cast(spec.count)) break; } if (spec.with_deletion && *removed_cnt > 0) { diff --git a/src/types/redis_zset.h b/src/types/redis_zset.h index 9282b608c05..5990580f852 100644 --- a/src/types/redis_zset.h +++ b/src/types/redis_zset.h @@ -118,7 +118,8 @@ class ZSet : public SubKeyScanner { uint64_t *removed_cnt); rocksdb::Status RangeByScore(const Slice &user_key, const RangeScoreSpec &spec, MemberScores *mscores, uint64_t *removed_cnt); - rocksdb::Status RangeByLex(const Slice &user_key, const RangeLexSpec &spec, Members *members, uint64_t *removed_cnt); + rocksdb::Status RangeByLex(const Slice &user_key, const RangeLexSpec &spec, MemberScores *mscores, + uint64_t *removed_cnt); private: rocksdb::ColumnFamilyHandle *score_cf_handle_; diff --git a/tests/cppunit/types/zset_test.cc b/tests/cppunit/types/zset_test.cc index ea0e7225072..f7e6e27ac53 100644 --- a/tests/cppunit/types/zset_test.cc +++ b/tests/cppunit/types/zset_test.cc @@ -175,44 +175,48 @@ TEST_F(RedisZSetTest, PopMax) { TEST_F(RedisZSetTest, RangeByLex) { uint64_t ret = 0; + uint64_t count = fields_.size(); std::vector mscores; for (size_t i = 0; i < fields_.size(); i++) { mscores.emplace_back(MemberScore{fields_[i].ToString(), scores_[i]}); } zset_->Add(key_, ZAddFlags::Default(), &mscores, &ret); - EXPECT_EQ(fields_.size(), ret); + EXPECT_EQ(count, ret); RangeLexSpec spec; spec.min = fields_[0].ToString(); spec.max = fields_[fields_.size() - 1].ToString(); - std::vector members; - zset_->RangeByLex(key_, spec, &members, nullptr); - EXPECT_EQ(members.size(), fields_.size()); - for (size_t i = 0; i < members.size(); i++) { - EXPECT_EQ(members[i], fields_[i].ToString()); + zset_->RangeByLex(key_, spec, &mscores, nullptr); + EXPECT_EQ(mscores.size(), fields_.size()); + for (size_t i = 0; i < mscores.size(); i++) { + EXPECT_EQ(mscores[i].member, fields_[i].ToString()); + EXPECT_EQ(mscores[i].score, scores_[i]); } spec.minex = true; - zset_->RangeByLex(key_, spec, &members, nullptr); - EXPECT_EQ(members.size(), fields_.size() - 1); - for (size_t i = 0; i < members.size(); i++) { - EXPECT_EQ(members[i], fields_[i + 1].ToString()); + zset_->RangeByLex(key_, spec, &mscores, nullptr); + EXPECT_EQ(mscores.size(), fields_.size() - 1); + for (size_t i = 0; i < mscores.size(); i++) { + EXPECT_EQ(mscores[i].member, fields_[i + 1].ToString()); + EXPECT_EQ(mscores[i].score, scores_[i + 1]); } spec.minex = false; spec.maxex = true; - zset_->RangeByLex(key_, spec, &members, nullptr); - EXPECT_EQ(members.size(), fields_.size() - 1); - for (size_t i = 0; i < members.size(); i++) { - EXPECT_EQ(members[i], fields_[i].ToString()); + zset_->RangeByLex(key_, spec, &mscores, nullptr); + EXPECT_EQ(mscores.size(), fields_.size() - 1); + for (size_t i = 0; i < mscores.size(); i++) { + EXPECT_EQ(mscores[i].member, fields_[i].ToString()); + EXPECT_EQ(mscores[i].score, scores_[i]); } spec.minex = true; spec.maxex = true; - zset_->RangeByLex(key_, spec, &members, nullptr); - EXPECT_EQ(members.size(), fields_.size() - 2); - for (size_t i = 0; i < members.size(); i++) { - EXPECT_EQ(members[i], fields_[i + 1].ToString()); + zset_->RangeByLex(key_, spec, &mscores, nullptr); + EXPECT_EQ(mscores.size(), fields_.size() - 2); + for (size_t i = 0; i < mscores.size(); i++) { + EXPECT_EQ(mscores[i].member, fields_[i + 1].ToString()); + EXPECT_EQ(mscores[i].score, scores_[i + 1]); } spec.minex = false; spec.maxex = false; @@ -220,10 +224,11 @@ TEST_F(RedisZSetTest, RangeByLex) { spec.max = "+"; spec.max_infinite = true; spec.reversed = true; - zset_->RangeByLex(key_, spec, &members, nullptr); - EXPECT_EQ(members.size(), fields_.size()); - for (size_t i = 0; i < members.size(); i++) { - EXPECT_EQ(members[i], fields_[6 - i].ToString()); + zset_->RangeByLex(key_, spec, &mscores, nullptr); + EXPECT_EQ(mscores.size(), fields_.size()); + for (size_t i = 0; i < mscores.size(); i++) { + EXPECT_EQ(mscores[i].member, fields_[count - i - 1].ToString()); + EXPECT_EQ(mscores[i].score, scores_[count - i - 1]); } zset_->Del(key_); From 7f649e22de5662d934e7cacd17e900d27bf251f9 Mon Sep 17 00:00:00 2001 From: jihuayu <8042833@qq.com> Date: Sat, 3 Jun 2023 20:08:41 +0800 Subject: [PATCH 11/11] update test --- tests/gocase/unit/type/zset/zset_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/gocase/unit/type/zset/zset_test.go b/tests/gocase/unit/type/zset/zset_test.go index 3a6a2f95b33..872e075ae03 100644 --- a/tests/gocase/unit/type/zset/zset_test.go +++ b/tests/gocase/unit/type/zset/zset_test.go @@ -401,10 +401,8 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s rdb.ZAdd(ctx, "zsrc", redis.Z{Score: 7, Member: "f"}) util.ErrorRegexp(t, rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: "xx", Stop: "ww"}).Err(), ".*not an integer.*") - util.ErrorRegexp(t, rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1}).Err(), ".*double.*") + util.ErrorRegexp(t, rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1}).Err(), ".*not an integer.*") util.ErrorRegexp(t, rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: 3, Count: 1, Offset: 1}).Err(), ".*error.*") - util.ErrorRegexp(t, rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: 3, Rev: true}).Err(), ".*double.*") - util.ErrorRegexp(t, rdb.ZRangeStore(ctx, "zdst", redis.ZRangeArgs{Key: "zsrc", Start: 1, Stop: 3, ByScore: true, ByLex: true}).Err(), ".*double.*") }) t.Run(fmt.Sprintf("ZRANGE basics - %s", encoding), func(t *testing.T) {