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 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
61 changes: 47 additions & 14 deletions libs/server/Resp/Objects/ListCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Text;
using System.Threading;
using Garnet.common;
using Tsavorite.core;

Expand Down Expand Up @@ -324,21 +325,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 +393,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
Loading