Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Compatibility] Added BRPOPLPUSH, ZREVRANGEBYLEX deprecated commands by mapping to existing commands #769

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
82 changes: 82 additions & 0 deletions libs/resources/RespCommandsDocs.json
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,37 @@
}
]
},
{
"Command": "BRPOPLPUSH",
"Name": "BRPOPLPUSH",
"Summary": "Pops an element from a list, pushes it to another list and returns it. Block until an element is available otherwise. Deletes the list if the last element was popped.",
"Group": "List",
"Complexity": "O(1)",
"DocFlags": "Deprecated",
"ReplacedBy": "\u0060BLMOVE\u0060 with the \u0060RIGHT\u0060 and \u0060LEFT\u0060 arguments",
"Arguments": [
{
"TypeDiscriminator": "RespCommandKeyArgument",
"Name": "SOURCE",
"DisplayText": "source",
"Type": "Key",
"KeySpecIndex": 0
},
{
"TypeDiscriminator": "RespCommandKeyArgument",
"Name": "DESTINATION",
"DisplayText": "destination",
"Type": "Key",
"KeySpecIndex": 1
},
{
"TypeDiscriminator": "RespCommandBasicArgument",
"Name": "TIMEOUT",
"DisplayText": "timeout",
"Type": "Double"
}
]
},
{
"Command": "CLIENT",
"Name": "CLIENT",
Expand Down Expand Up @@ -5872,6 +5903,57 @@
}
]
},
{
"Command": "ZREVRANGEBYLEX",
"Name": "ZREVRANGEBYLEX",
"Summary": "Returns members in a sorted set within a lexicographical range in reverse order.",
"Group": "SortedSet",
"Complexity": "O(log(N)\u002BM) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).",
"DocFlags": "Deprecated",
"ReplacedBy": "\u0060ZRANGE\u0060 with the \u0060REV\u0060 and \u0060BYLEX\u0060 arguments",
"Arguments": [
{
"TypeDiscriminator": "RespCommandKeyArgument",
"Name": "KEY",
"DisplayText": "key",
"Type": "Key",
"KeySpecIndex": 0
},
{
"TypeDiscriminator": "RespCommandBasicArgument",
"Name": "MAX",
"DisplayText": "max",
"Type": "String"
},
{
"TypeDiscriminator": "RespCommandBasicArgument",
"Name": "MIN",
"DisplayText": "min",
"Type": "String"
},
{
"TypeDiscriminator": "RespCommandContainerArgument",
"Name": "LIMIT",
"Type": "Block",
"Token": "LIMIT",
"ArgumentFlags": "Optional",
"Arguments": [
{
"TypeDiscriminator": "RespCommandBasicArgument",
"Name": "OFFSET",
"DisplayText": "offset",
"Type": "Integer"
},
{
"TypeDiscriminator": "RespCommandBasicArgument",
"Name": "COUNT",
"DisplayText": "count",
"Type": "Integer"
}
]
}
]
},
{
"Command": "ZREVRANGEBYSCORE",
"Name": "ZREVRANGEBYSCORE",
Expand Down
63 changes: 63 additions & 0 deletions libs/resources/RespCommandsInfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,44 @@
}
]
},
{
"Command": "BRPOPLPUSH",
"Name": "BRPOPLPUSH",
"Arity": 4,
"Flags": "Blocking, DenyOom, Write",
"FirstKey": 1,
"LastKey": 2,
"Step": 1,
"AclCategories": "Blocking, List, Slow, Write",
"KeySpecifications": [
{
"BeginSearch": {
"TypeDiscriminator": "BeginSearchIndex",
"Index": 1
},
"FindKeys": {
"TypeDiscriminator": "FindKeysRange",
"LastKey": 0,
"KeyStep": 1,
"Limit": 0
},
"Flags": "RW, Access, Delete"
},
{
"BeginSearch": {
"TypeDiscriminator": "BeginSearchIndex",
"Index": 2
},
"FindKeys": {
"TypeDiscriminator": "FindKeysRange",
"LastKey": 0,
"KeyStep": 1,
"Limit": 0
},
"Flags": "RW, Insert"
}
]
},
{
"Command": "CLIENT",
"Name": "CLIENT",
Expand Down Expand Up @@ -4476,6 +4514,31 @@
}
]
},
{
"Command": "ZREVRANGEBYLEX",
"Name": "ZREVRANGEBYLEX",
"Arity": -4,
"Flags": "ReadOnly",
"FirstKey": 1,
"LastKey": 1,
"Step": 1,
"AclCategories": "Read, SortedSet, Slow",
"KeySpecifications": [
{
"BeginSearch": {
"TypeDiscriminator": "BeginSearchIndex",
"Index": 1
},
"FindKeys": {
"TypeDiscriminator": "FindKeysRange",
"LastKey": 0,
"KeyStep": 1,
"Limit": 0
},
"Flags": "RO, Access"
}
]
},
{
"Command": "ZREVRANGEBYSCORE",
"Name": "ZREVRANGEBYSCORE",
Expand Down
4 changes: 4 additions & 0 deletions libs/server/Resp/CmdStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ static partial class CmdStrings
public static ReadOnlySpan<byte> CHANNELS => "CHANNELS"u8;
public static ReadOnlySpan<byte> NUMPAT => "NUMPAT"u8;
public static ReadOnlySpan<byte> NUMSUB => "NUMSUB"u8;
public static ReadOnlySpan<byte> RIGHT => "RIGHT"u8;
public static ReadOnlySpan<byte> LEFT => "LEFT"u8;
public static ReadOnlySpan<byte> BYLEX => "BYLEX"u8;
public static ReadOnlySpan<byte> REV => "REV"u8;

/// <summary>
/// Response strings
Expand Down
21 changes: 21 additions & 0 deletions libs/server/Resp/Objects/ListCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,27 @@ private unsafe bool ListBlockingMove(RespCommand command)
return true;
}

/// <summary>
/// BRPOPLPUSH
/// </summary>
/// <returns></returns>
private bool ListBlockingPopPush()
{
if (parseState.Count != 3)
{
return AbortWithWrongNumberOfArguments(nameof(RespCommand.BRPOPLPUSH));
}

var srcKey = parseState.GetArgSliceByRef(0);
var dstKey = parseState.GetArgSliceByRef(1);
var rightOption = ArgSlice.FromPinnedSpan(CmdStrings.RIGHT);
var leftOption = ArgSlice.FromPinnedSpan(CmdStrings.LEFT);
var timeout = parseState.GetArgSliceByRef(2);
parseState.InitializeWithArguments(srcKey, dstKey, rightOption, leftOption, timeout);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why create a new parse state with the direction arguments and then call ListBlockingMove to reparse them once again? Just create the cmdArgs array and call the itemBroker directly. Alternatively, you can create a common method that takes the 5 arguments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I will do it, I did it in this way because there are deprecated commands and the only purpose of adding these is additioning compatibility still there commands are removed as discussed in this GitHub command #684 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize these are deprecated commands. Still, it's better to have good practices throughout so that other contributors can use them as reference :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


return ListBlockingMove(RespCommand.BLMOVE);
}

/// <summary>
/// LLEN key
/// Gets the length of the list stored at key.
Expand Down
47 changes: 47 additions & 0 deletions libs/server/Resp/Objects/SortedSetCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,53 @@ private unsafe bool SortedSetRange<TGarnetApi>(RespCommand command, ref TGarnetA
return true;
}

/// <summary>
/// ZREVRANGEBYLEX
/// </summary>
/// <typeparam name="TGarnetApi"></typeparam>
/// <param name="storageApi"></param>
/// <returns></returns>
private bool ListRangeByLength<TGarnetApi>(ref TGarnetApi storageApi)
where TGarnetApi : IGarnetApi
{
if (parseState.Count is not (3 or 6))
{
return AbortWithWrongNumberOfArguments(nameof(RespCommand.ZREVRANGEBYLEX));
}


var sbKey = parseState.GetArgSliceByRef(0);
var start = parseState.GetArgSliceByRef(1);
var stop = parseState.GetArgSliceByRef(2);
var byLenOption = ArgSlice.FromPinnedSpan(CmdStrings.BYLEX);
var revOption = ArgSlice.FromPinnedSpan(CmdStrings.REV);

// ZREVRANGEBYLEX key start stop
if (parseState.Count == 3)
{
parseState.InitializeWithArguments(sbKey, start, stop, byLenOption, revOption);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, no need to initialize a new parse state, actually no need for this method at all, just create a new SortedSetOperation - ZREVRANGEBYLEX and call SortedSetRange directy, then handle that specific op in SortedSetObjectImpl.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


return SortedSetRange(RespCommand.ZRANGE, ref storageApi);
}

// ZREVRANGEBYLEX key start stop [LIMIT offset count]
var limit = parseState.GetArgSliceByRef(3);
var offset = parseState.GetArgSliceByRef(4);
var count = parseState.GetArgSliceByRef(5);

parseState.Initialize(8);
parseState.SetArgument(0, sbKey);
parseState.SetArgument(1, start);
parseState.SetArgument(2, stop);
parseState.SetArgument(3, byLenOption);
parseState.SetArgument(4, revOption);
parseState.SetArgument(5, limit);
parseState.SetArgument(6, offset);
parseState.SetArgument(7, count);

return SortedSetRange(RespCommand.ZRANGE, ref storageApi);
}

/// <summary>
/// Returns the score of member in the sorted set at key.
/// If member does not exist in the sorted set, or key does not exist, nil is returned.
Expand Down
10 changes: 10 additions & 0 deletions libs/server/Resp/Parser/RespCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public enum RespCommand : ushort
ZRANGEBYSCORE,
ZRANK,
ZREVRANGE,
ZREVRANGEBYLEX,
ZREVRANGEBYSCORE,
ZREVRANK,
ZSCAN,
Expand Down Expand Up @@ -121,6 +122,7 @@ public enum RespCommand : ushort
BLPOP,
BRPOP,
BLMOVE,
BRPOPLPUSH,
MIGRATE,
MSET,
MSETNX,
Expand Down Expand Up @@ -1365,6 +1367,10 @@ private RespCommand FastParseArrayCommand(ref int count, ref ReadOnlySpan<byte>
{
return RespCommand.ZDIFFSTORE;
}
else if (*(ulong*)(ptr + 1) == MemoryMarshal.Read<ulong>("10\r\nBRPO"u8) && *(uint*)(ptr + 9) == MemoryMarshal.Read<uint>("PLPUSH\r\n"u8))
{
return RespCommand.BRPOPLPUSH;
}
break;

case 11:
Expand Down Expand Up @@ -1425,6 +1431,10 @@ private RespCommand FastParseArrayCommand(ref int count, ref ReadOnlySpan<byte>
{
return RespCommand.ZREMRANGEBYLEX;
}
else if (*(ulong*)(ptr + 3) == MemoryMarshal.Read<ulong>("\r\nZREVRA"u8) && *(ulong*)(ptr + 11) == MemoryMarshal.Read<ulong>("NGEBYLEX"u8) && *(ushort*)(ptr + 19) == MemoryMarshal.Read<ushort>("\r\n"u8))
{
return RespCommand.ZREVRANGEBYLEX;
}
break;

case 15:
Expand Down
2 changes: 2 additions & 0 deletions libs/server/Resp/RespServerSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ private bool ProcessArrayCommands<TGarnetApi>(RespCommand cmd, ref TGarnetApi st
RespCommand.LLEN => ListLength(ref storageApi),
RespCommand.LTRIM => ListTrim(ref storageApi),
RespCommand.LRANGE => ListRange(ref storageApi),
RespCommand.ZREVRANGEBYLEX => ListRangeByLength(ref storageApi),
RespCommand.LINDEX => ListIndex(ref storageApi),
RespCommand.LINSERT => ListInsert(ref storageApi),
RespCommand.LREM => ListRemove(ref storageApi),
Expand All @@ -647,6 +648,7 @@ private bool ProcessArrayCommands<TGarnetApi>(RespCommand cmd, ref TGarnetApi st
RespCommand.BLPOP => ListBlockingPop(cmd),
RespCommand.BRPOP => ListBlockingPop(cmd),
RespCommand.BLMOVE => ListBlockingMove(cmd),
RespCommand.BRPOPLPUSH => ListBlockingPopPush(),
// Hash Commands
RespCommand.HSET => HashSet(cmd, ref storageApi),
RespCommand.HMSET => HashSet(cmd, ref storageApi),
Expand Down
2 changes: 2 additions & 0 deletions playground/CommandInfoUpdater/SupportedCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class SupportedCommand
new("BLPOP", RespCommand.BLPOP),
new("BRPOP", RespCommand.BRPOP),
new("BLMOVE", RespCommand.BLMOVE),
new("BRPOPLPUSH", RespCommand.BRPOPLPUSH),
new("CLIENT", RespCommand.CLIENT,
[
new("CLIENT|ID", RespCommand.CLIENT_ID),
Expand Down Expand Up @@ -275,6 +276,7 @@ public class SupportedCommand
new("ZREMRANGEBYRANK", RespCommand.ZREMRANGEBYRANK),
new("ZREMRANGEBYSCORE", RespCommand.ZREMRANGEBYSCORE),
new("ZREVRANGE", RespCommand.ZREVRANGE),
new("ZREVRANGEBYLEX", RespCommand.ZREVRANGEBYLEX),
new("ZREVRANGEBYSCORE", RespCommand.ZREVRANGEBYSCORE),
new("ZREVRANK", RespCommand.ZREVRANK),
new("ZSCAN", RespCommand.ZSCAN),
Expand Down
47 changes: 47 additions & 0 deletions test/Garnet.test.cluster/RedirectTests/BaseCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1396,6 +1396,35 @@ public override ArraySegment<string>[] SetupSingleSlotRequest()
}
}

internal class BRPOPLPUSH : BaseCommand
{
public override bool IsArrayCommand => true;
public override bool ArrayResponse => false;
public override string Command => nameof(BRPOPLPUSH);

public override string[] GetSingleSlotRequest()
{
var ssk = GetSingleSlotKeys;
return [ssk[0], ssk[1], "1"];
}

public override string[] GetCrossSlotRequest()
{
var csk = GetCrossSlotKeys;
return [csk[0], csk[1], "1"];
}

public override ArraySegment<string>[] SetupSingleSlotRequest()
{
var ssk = GetSingleSlotKeys;
var setup = new ArraySegment<string>[3];
setup[0] = new ArraySegment<string>(["LPUSH", ssk[1], "value1", "value2", "value3"]);
setup[1] = new ArraySegment<string>(["LPUSH", ssk[2], "value4", "value5", "value6"]);
setup[2] = new ArraySegment<string>(["LPUSH", ssk[3], "value7", "value8", "value9"]);
return setup;
}
}

internal class LLEN : BaseCommand
{
public override bool IsArrayCommand => false;
Expand Down Expand Up @@ -1685,6 +1714,24 @@ public override string[] GetSingleSlotRequest()
public override ArraySegment<string>[] SetupSingleSlotRequest() => throw new NotImplementedException();
}

internal class ZREVRANGEBYLEX : BaseCommand
{
public override bool IsArrayCommand => false;
public override bool ArrayResponse => true;
public override string Command => nameof(ZREVRANGEBYLEX);

public override string[] GetSingleSlotRequest()
{
var ssk = GetSingleSlotKeys;
// ZREVRANGEBYLEX x 0 -1
return [ssk[0], "0", "-1"];
}

public override string[] GetCrossSlotRequest() => throw new NotImplementedException();

public override ArraySegment<string>[] SetupSingleSlotRequest() => throw new NotImplementedException();
}

internal class ZSCORE : BaseCommand
{
public override bool IsArrayCommand => false;
Expand Down
Loading