Skip to content

Commit

Permalink
[Compatibility] Added BRPOPLPUSH, ZREVRANGEBYLEX deprecated commands …
Browse files Browse the repository at this point in the history
…by mapping to existing commands (#769)

* Added BRPOPLPUSH, ZREVRANGEBYLEX deprecated commands by mapping to existing commends

* Fixed build issue

* Review comment fixes

* Add link in doc for SUBSTR

* removing unnecessary using

---------

Co-authored-by: Tal Zaccai <[email protected]>
  • Loading branch information
Vijay-Nirmal and TalZaccai authored Dec 4, 2024
1 parent 4ace011 commit 79d12e8
Show file tree
Hide file tree
Showing 19 changed files with 475 additions and 19 deletions.
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 @@ -6093,6 +6124,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 @@ -4514,6 +4552,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
2 changes: 2 additions & 0 deletions libs/server/Objects/SortedSet/SortedSetObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public enum SortedSetOperation : byte
GEOSEARCH,
GEOSEARCHSTORE,
ZREVRANGE,
ZREVRANGEBYLEX,
ZREVRANGEBYSCORE,
ZREVRANK,
ZREMRANGEBYLEX,
Expand Down Expand Up @@ -280,6 +281,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory
case SortedSetOperation.ZREVRANGE:
SortedSetRange(ref input, ref output);
break;
case SortedSetOperation.ZREVRANGEBYLEX:
case SortedSetOperation.ZREVRANGEBYSCORE:
SortedSetRange(ref input, ref output);
break;
Expand Down
4 changes: 4 additions & 0 deletions libs/server/Objects/SortedSet/SortedSetObjectImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,10 @@ private void SortedSetRange(ref ObjectInput input, ref SpanByteAndMemory output)
options.ByScore = true;
options.Reverse = true;
break;
case SortedSetOperation.ZREVRANGEBYLEX:
options.ByLex = true;
options.Reverse = true;
break;
}

if (count > 2)
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 @@ -111,6 +111,10 @@ static partial class CmdStrings
public static ReadOnlySpan<byte> STOREDIST => "STOREDIST"u8;
public static ReadOnlySpan<byte> WITHDIST => "WITHDIST"u8;
public static ReadOnlySpan<byte> WITHHASH => "WITHHASH"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
60 changes: 46 additions & 14 deletions libs/server/Resp/Objects/ListCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,21 +324,60 @@ private bool ListBlockingPop(RespCommand command)
return true;
}

private unsafe bool ListBlockingMove(RespCommand command)
private unsafe bool ListBlockingMove()
{
if (parseState.Count != 5)
{
return AbortWithWrongNumberOfArguments(command.ToString());
return AbortWithWrongNumberOfArguments(nameof(RespCommand.BLMOVE));
}

var cmdArgs = new ArgSlice[] { default, default, default };
var srcKey = parseState.GetArgSliceByRef(0);
var dstKey = parseState.GetArgSliceByRef(1);
var srcDir = parseState.GetArgSliceByRef(2);
var dstDir = parseState.GetArgSliceByRef(3);

if (!parseState.TryGetDouble(4, out var timeout))
{
while (!RespWriteUtils.WriteError(CmdStrings.RESP_ERR_TIMEOUT_NOT_VALID_FLOAT, ref dcurr, dend))
SendAndReset();
return true;
}

return ListBlockingMove(srcKey, dstKey, srcDir, dstDir, timeout);
}

/// <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);

if (!parseState.TryGetDouble(2, out var timeout))
{
while (!RespWriteUtils.WriteError(CmdStrings.RESP_ERR_TIMEOUT_NOT_VALID_FLOAT, ref dcurr, dend))
SendAndReset();
return true;
}

return ListBlockingMove(srcKey, dstKey, rightOption, leftOption, timeout);
}

private bool ListBlockingMove(ArgSlice srcKey, ArgSlice dstKey, ArgSlice srcDir, ArgSlice dstDir, double timeout)
{
var cmdArgs = new ArgSlice[] { default, default, default };

// Read destination key
cmdArgs[0] = parseState.GetArgSliceByRef(1);
var srcDir = parseState.GetArgSliceByRef(2);
var dstDir = parseState.GetArgSliceByRef(3);
cmdArgs[0] = dstKey;

var sourceDirection = GetOperationDirection(srcDir);
var destinationDirection = GetOperationDirection(dstDir);
Expand All @@ -353,17 +392,10 @@ private unsafe bool ListBlockingMove(RespCommand command)
cmdArgs[1] = new ArgSlice(pSrcDir, 1);
cmdArgs[2] = new ArgSlice(pDstDir, 1);

if (!parseState.TryGetDouble(4, out var timeout))
{
while (!RespWriteUtils.WriteError(CmdStrings.RESP_ERR_TIMEOUT_NOT_VALID_FLOAT, ref dcurr, dend))
SendAndReset();
return true;
}

if (storeWrapper.itemBroker == null)
throw new GarnetException("Object store is disabled");

var result = storeWrapper.itemBroker.MoveCollectionItemAsync(command, srcKey.ToArray(), this, timeout,
var result = storeWrapper.itemBroker.MoveCollectionItemAsync(RespCommand.BLMOVE, srcKey.ToArray(), this, timeout,
cmdArgs).Result;

if (!result.Found)
Expand Down
1 change: 1 addition & 0 deletions libs/server/Resp/Objects/SortedSetCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ private unsafe bool SortedSetRange<TGarnetApi>(RespCommand command, ref TGarnetA
RespCommand.ZRANGE => SortedSetOperation.ZRANGE,
RespCommand.ZREVRANGE => SortedSetOperation.ZREVRANGE,
RespCommand.ZRANGEBYSCORE => SortedSetOperation.ZRANGEBYSCORE,
RespCommand.ZREVRANGEBYLEX => SortedSetOperation.ZREVRANGEBYLEX,
RespCommand.ZREVRANGEBYSCORE => SortedSetOperation.ZREVRANGEBYSCORE,
_ => throw new Exception($"Unexpected {nameof(SortedSetOperation)}: {command}")
};
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 @@ -122,6 +123,7 @@ public enum RespCommand : ushort
BLPOP,
BRPOP,
BLMOVE,
BRPOPLPUSH,
MIGRATE,
MSET,
MSETNX,
Expand Down Expand Up @@ -1366,6 +1368,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 @@ -1430,6 +1436,10 @@ private RespCommand FastParseArrayCommand(ref int count, ref ReadOnlySpan<byte>
{
return RespCommand.GEOSEARCHSTORE;
}
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
4 changes: 3 additions & 1 deletion libs/server/Resp/RespServerSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ private bool ProcessArrayCommands<TGarnetApi>(RespCommand cmd, ref TGarnetApi st
RespCommand.ZDIFF => SortedSetDifference(ref storageApi),
RespCommand.ZDIFFSTORE => SortedSetDifferenceStore(ref storageApi),
RespCommand.ZREVRANGE => SortedSetRange(cmd, ref storageApi),
RespCommand.ZREVRANGEBYLEX => SortedSetRange(cmd, ref storageApi),
RespCommand.ZREVRANGEBYSCORE => SortedSetRange(cmd, ref storageApi),
RespCommand.ZSCAN => ObjectScan(GarnetObjectType.SortedSet, ref storageApi),
//SortedSet for Geo Commands
Expand Down Expand Up @@ -649,7 +650,8 @@ private bool ProcessArrayCommands<TGarnetApi>(RespCommand cmd, ref TGarnetApi st
RespCommand.LSET => ListSet(ref storageApi),
RespCommand.BLPOP => ListBlockingPop(cmd),
RespCommand.BRPOP => ListBlockingPop(cmd),
RespCommand.BLMOVE => ListBlockingMove(cmd),
RespCommand.BLMOVE => ListBlockingMove(),
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 libs/server/Transaction/TxnKeyManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ internal int GetKeys(RespCommand command, int inputCount, out ReadOnlySpan<byte>
RespCommand.GEOPOS => SortedSetObjectKeys(SortedSetOperation.GEOPOS, inputCount),
RespCommand.GEOSEARCH => SortedSetObjectKeys(SortedSetOperation.GEOSEARCH, inputCount),
RespCommand.ZREVRANGE => SortedSetObjectKeys(SortedSetOperation.ZREVRANGE, inputCount),
RespCommand.ZREVRANGEBYLEX => SortedSetObjectKeys(SortedSetOperation.ZREVRANGEBYLEX, inputCount),
RespCommand.ZREVRANGEBYSCORE => SortedSetObjectKeys(SortedSetOperation.ZREVRANGEBYSCORE, inputCount),
RespCommand.LINDEX => ListObjectKeys((byte)ListOperation.LINDEX),
RespCommand.LINSERT => ListObjectKeys((byte)ListOperation.LINSERT),
Expand Down Expand Up @@ -219,6 +220,7 @@ private int SortedSetObjectKeys(SortedSetOperation command, int inputCount)
SortedSetOperation.GEOPOS => SingleKey(1, true, LockType.Shared),
SortedSetOperation.GEOSEARCH => SingleKey(1, true, LockType.Shared),
SortedSetOperation.ZREVRANGE => SingleKey(1, true, LockType.Shared),
SortedSetOperation.ZREVRANGEBYLEX => SingleKey(1, true, LockType.Shared),
SortedSetOperation.ZREVRANGEBYSCORE => SingleKey(1, true, LockType.Shared),
_ => -1
};
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 @@ -276,6 +277,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
Loading

0 comments on commit 79d12e8

Please sign in to comment.