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

ZMPOP and LMPOP #2094

Merged
merged 30 commits into from
Apr 19, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8d6de09
Adding ZMPOP and LMPOP
slorello89 Apr 14, 2022
48c25bc
merge conflicts
slorello89 Apr 14, 2022
17749fc
trying to reset whitespace changes
slorello89 Apr 15, 2022
1bd5b8b
removing new() syntax
slorello89 Apr 15, 2022
fcf8642
reverting whitespace addition to csproj
slorello89 Apr 15, 2022
916240b
nick's comment updates
slorello89 Apr 15, 2022
8db54f8
adding Null values for newly renamed ListEntries and SortedSetEntries
slorello89 Apr 15, 2022
2818e06
possible solution for key-conflict?
slorello89 Apr 15, 2022
872742d
Docs/tweaks
NickCraver Apr 16, 2022
924218d
Merge branch 'main' into feature/ZMPOP
NickCraver Apr 16, 2022
aeba2a8
Simplify tests
NickCraver Apr 16, 2022
63e6679
SortedSetEntries -> SortedSetPopResult ListEntries -> ListPopResult
slorello89 Apr 16, 2022
321b1fe
Docs and ordering
NickCraver Apr 16, 2022
7716091
Null value updates for the .Null case
NickCraver Apr 16, 2022
6d48c1a
Simplify the procesorrrrrrrrrrrrs
NickCraver Apr 16, 2022
aca1da0
Optimize harder
NickCraver Apr 16, 2022
19d69d3
Merge remote-tracking branch 'origin/main' into feature/ZMPOP
NickCraver Apr 16, 2022
d6378dd
Add release notes
NickCraver Apr 16, 2022
0a6f154
Grammar, lest Elise kills me in my sleep
NickCraver Apr 16, 2022
88810ed
Simplify descriptions
NickCraver Apr 16, 2022
fd8db50
Must was so angry.
NickCraver Apr 16, 2022
a6ef27b
Test tweaks
NickCraver Apr 16, 2022
2991bd8
Tests: remove additional LINQ (makes tests more specific too)
NickCraver Apr 16, 2022
0779e45
SortedSets: de-LINQ
NickCraver Apr 16, 2022
be67266
Optimize SortedSet tests
NickCraver Apr 16, 2022
e682f33
Use \Results folder
NickCraver Apr 16, 2022
d7726ce
Results -> API types
NickCraver Apr 16, 2022
717dd6f
Merge remote-tracking branch 'origin/main' into feature/ZMPOP
NickCraver Apr 17, 2022
a8e435e
Merge remote-tracking branch 'origin/main' into feature/ZMPOP
NickCraver Apr 19, 2022
0e26598
Merge remote-tracking branch 'origin/main' into feature/ZMPOP
NickCraver Apr 19, 2022
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
2 changes: 2 additions & 0 deletions src/StackExchange.Redis/Enums/RedisCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ internal enum RedisCommand
LINSERT,
LLEN,
LMOVE,
LMPOP,
LPOP,
LPOS,
LPUSH,
Expand Down Expand Up @@ -207,6 +208,7 @@ internal enum RedisCommand
ZINTERCARD,
ZINTERSTORE,
ZLEXCOUNT,
ZMPOP,
ZMSCORE,
ZPOPMAX,
ZPOPMIN,
Expand Down
38 changes: 38 additions & 0 deletions src/StackExchange.Redis/Interfaces/IDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,19 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <remarks>https://redis.io/commands/lpop</remarks>
RedisValue[] ListLeftPop(RedisKey key, long count, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Removes and returns at most specified <paramref name="count"/> of elements from the first non-empty list
/// within the set of <paramref name="keys"/> passed into it.
/// Starts on the left side of the list.
/// If the length of the first non-empty list is less than <paramref name="count"/>, only the elements within that list are returned.
Copy link
Collaborator

@NickCraver NickCraver Apr 16, 2022

Choose a reason for hiding this comment

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

@slorello89 Does this matter? e.g. is it equally correct and maybe clearer to simplify to:

Only the elements from the first non-empty list are ever returned, even if <paramref name="count"/> is higher than its length.

...or is that more confusing and/or plain wrong?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The important point is that the first list it encounters is what it pops elements out of. Both ways of phrasing it get at that point so whichever is simpler.

Copy link
Collaborator

Choose a reason for hiding this comment

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

kk - to me it's confusing currently - will adjust, can always change again!

/// </summary>
/// <param name="keys">The keys to look through for elements to pop.</param>
/// <param name="count">The maximum number of elements to pop from the list.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>A span of contiguous elements from the list, or <see cref="ListPopResult.Null"/> if no non-empty lists are found.</returns>
/// <remarks>https://redis.io/commands/lmpop</remarks>
ListPopResult ListLeftPop(RedisKey[] keys, long count, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Scans through the list stored at <paramref name="key"/> looking for <paramref name="element"/>, returning the 0-based
/// index of the first matching element.
Expand Down Expand Up @@ -973,6 +986,19 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <remarks>https://redis.io/commands/rpop</remarks>
RedisValue[] ListRightPop(RedisKey key, long count, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Removes and returns at most specified <paramref name="count"/> of elements from the first non-empty list
/// within the set of <paramref name="keys"/> passed into it.
/// Starts on the right side of the list.
/// If the length of the first non-empty list is less than <paramref name="count"/>, only the elements within that list are returned.
/// </summary>
/// <param name="keys">The keys to look through for elements to pop.</param>
/// <param name="count">The maximum number of elements to pop from the list.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>A span of contiguous elements from the list, or <see cref="ListPopResult.Null"/> if no non-empty lists are found.</returns>
/// <remarks>https://redis.io/commands/lmpop</remarks>
ListPopResult ListRightPop(RedisKey[] keys, long count, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Atomically returns and removes the last element (tail) of the list stored at source, and pushes the element at the first element (head) of the list stored at destination.
/// </summary>
Expand Down Expand Up @@ -1981,6 +2007,18 @@ IEnumerable<SortedSetEntry> SortedSetScan(RedisKey key,
/// <remarks>https://redis.io/commands/zpopmax</remarks>
SortedSetEntry[] SortedSetPop(RedisKey key, long count, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Removes and returns up to <paramref name="count"/> entries from the first non-empty sorted set in <paramref name="keys"/>.
/// Returns <see cref="SortedSetPopResult.Null"/> if none of the sets exist or contain any elements.
/// </summary>
/// <param name="keys">The keys to check.</param>
/// <param name="count">The maximum number of records to pop out of the sorted set.</param>
/// <param name="order">The order to sort by when popping items out of the set.</param>
/// <param name="flags">The flags to use for the operation.</param>
/// <returns>A contiguous collection of sorted set entries with the key they were popped from, or <see cref="SortedSetPopResult.Null"/> if no non-empty sorted sets are found.</returns>
/// <remarks>https://redis.io/commands/zmpop</remarks>
SortedSetPopResult SortedSetPop(RedisKey[] keys, long count, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Allow the consumer to mark a pending message as correctly processed. Returns the number of messages acknowledged.
/// </summary>
Expand Down
38 changes: 38 additions & 0 deletions src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,19 @@ public interface IDatabaseAsync : IRedisAsync
/// <remarks>https://redis.io/commands/lpop</remarks>
Task<RedisValue[]> ListLeftPopAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Removes and returns at most specified <paramref name="count"/> of elements from the first non-empty list
/// within the set of <paramref name="keys"/> passed into it.
/// Starts on the left side of the list.
/// If the length of the first non-empty list is less than <paramref name="count"/>, only the elements within that list are returned.
/// </summary>
/// <param name="keys">The keys to look through for elements to pop.</param>
/// <param name="count">The maximum number of elements to pop from the list.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>A span of contiguous elements from the list, or <see cref="ListPopResult.Null"/> if no non-empty lists are found.</returns>
/// <remarks>https://redis.io/commands/lmpop</remarks>
Task<ListPopResult> ListLeftPopAsync(RedisKey[] keys, long count, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Scans through the list stored at <paramref name="key"/> looking for <paramref name="element"/>, returning the 0-based
/// index of the first matching element.
Expand Down Expand Up @@ -949,6 +962,19 @@ public interface IDatabaseAsync : IRedisAsync
/// <remarks>https://redis.io/commands/rpop</remarks>
Task<RedisValue[]> ListRightPopAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Removes and returns at most specified <paramref name="count"/> of elements from the first non-empty list
/// within the set of <paramref name="keys"/> passed into it.
/// Starts on the right side of the list.
/// If the length of the first non-empty list is less than <paramref name="count"/>, only the elements within that list are returned.
/// </summary>
/// <param name="keys">The keys to look through for elements to pop.</param>
/// <param name="count">The maximum number of elements to pop from the list.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>A span of contiguous elements from the list, or <see cref="ListPopResult.Null"/> if no non-empty lists are found.</returns>
/// <remarks>https://redis.io/commands/lmpop</remarks>
Task<ListPopResult> ListRightPopAsync(RedisKey[] keys, long count, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Atomically returns and removes the last element (tail) of the list stored at source, and pushes the element at the first element (head) of the list stored at destination.
/// </summary>
Expand Down Expand Up @@ -1933,6 +1959,18 @@ IAsyncEnumerable<SortedSetEntry> SortedSetScanAsync(RedisKey key,
/// <remarks>https://redis.io/commands/zpopmax</remarks>
Task<SortedSetEntry[]> SortedSetPopAsync(RedisKey key, long count, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Removes and returns up to <paramref name="count"/> entries from the first non-empty sorted set in <paramref name="keys"/>.
/// Returns <see cref="SortedSetPopResult.Null"/> if none of the sets exist or contain any elements.
/// </summary>
/// <param name="keys">The keys to check.</param>
/// <param name="count">The maximum number of records to pop out of the sorted set.</param>
/// <param name="order">The order to sort by when popping items out of the set.</param>
/// <param name="flags">The flags to use for the operation.</param>
/// <returns>A contiguous collection of sorted set entries with the key they were popped from, or <see cref="SortedSetPopResult.Null"/> if no non-empty sorted sets are found.</returns>
/// <remarks>https://redis.io/commands/zmpop</remarks>
Task<SortedSetPopResult> SortedSetPopAsync(RedisKey[] keys, long count, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Allow the consumer to mark a pending message as correctly processed. Returns the number of messages acknowledged.
/// </summary>
Expand Down
9 changes: 9 additions & 0 deletions src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ public RedisValue ListLeftPop(RedisKey key, CommandFlags flags = CommandFlags.No
public RedisValue[] ListLeftPop(RedisKey key, long count, CommandFlags flags = CommandFlags.None) =>
Inner.ListLeftPop(ToInner(key), count, flags);

public ListPopResult ListLeftPop(RedisKey[] keys, long count, CommandFlags flags = CommandFlags.None) =>
Inner.ListLeftPop(ToInner(keys), count, flags);

public long ListPosition(RedisKey key, RedisValue element, long rank = 1, long maxLength = 0, CommandFlags flags = CommandFlags.None) =>
Inner.ListPosition(ToInner(key), element, rank, maxLength, flags);

Expand Down Expand Up @@ -251,6 +254,9 @@ public RedisValue ListRightPop(RedisKey key, CommandFlags flags = CommandFlags.N
public RedisValue[] ListRightPop(RedisKey key, long count, CommandFlags flags = CommandFlags.None) =>
Inner.ListRightPop(ToInner(key), count, flags);

public ListPopResult ListRightPop(RedisKey[] keys, long count, CommandFlags flags = CommandFlags.None) =>
Inner.ListRightPop(ToInner(keys), count, flags);

public RedisValue ListRightPopLeftPush(RedisKey source, RedisKey destination, CommandFlags flags = CommandFlags.None) =>
Inner.ListRightPopLeftPush(ToInner(source), ToInner(destination), flags);

Expand Down Expand Up @@ -475,6 +481,9 @@ public long SortedSetRemoveRangeByValue(RedisKey key, RedisValue min, RedisValue
public SortedSetEntry[] SortedSetPop(RedisKey key, long count, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None) =>
Inner.SortedSetPop(ToInner(key), count, order, flags);

public SortedSetPopResult SortedSetPop(RedisKey[] keys, long count, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None) =>
Inner.SortedSetPop(ToInner(keys), count, order, flags);

public long StreamAcknowledge(RedisKey key, RedisValue groupName, RedisValue messageId, CommandFlags flags = CommandFlags.None) =>
Inner.StreamAcknowledge(ToInner(key), groupName, messageId, flags);

Expand Down
9 changes: 9 additions & 0 deletions src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ public Task<RedisValue> ListLeftPopAsync(RedisKey key, CommandFlags flags = Comm
public Task<RedisValue[]> ListLeftPopAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None) =>
Inner.ListLeftPopAsync(ToInner(key), count, flags);

public Task<ListPopResult> ListLeftPopAsync(RedisKey[] keys, long count, CommandFlags flags = CommandFlags.None) =>
Inner.ListLeftPopAsync(ToInner(keys), count, flags);

public Task<long> ListPositionAsync(RedisKey key, RedisValue element, long rank = 1, long maxLength = 0, CommandFlags flags = CommandFlags.None) =>
Inner.ListPositionAsync(ToInner(key), element, rank, maxLength, flags);

Expand Down Expand Up @@ -262,6 +265,9 @@ public Task<RedisValue> ListRightPopAsync(RedisKey key, CommandFlags flags = Com
public Task<RedisValue[]> ListRightPopAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None) =>
Inner.ListRightPopAsync(ToInner(key), count, flags);

public Task<ListPopResult> ListRightPopAsync(RedisKey[] keys, long count, CommandFlags flags = CommandFlags.None) =>
Inner.ListRightPopAsync(ToInner(keys), count, flags);

public Task<RedisValue> ListRightPopLeftPushAsync(RedisKey source, RedisKey destination, CommandFlags flags = CommandFlags.None) =>
Inner.ListRightPopLeftPushAsync(ToInner(source), ToInner(destination), flags);

Expand Down Expand Up @@ -492,6 +498,9 @@ public IAsyncEnumerable<SortedSetEntry> SortedSetScanAsync(RedisKey key, RedisVa
public Task<SortedSetEntry[]> SortedSetPopAsync(RedisKey key, long count, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None) =>
Inner.SortedSetPopAsync(ToInner(key), count, order, flags);

public Task<SortedSetPopResult> SortedSetPopAsync(RedisKey[] keys, long count, Order order = Order.Ascending, CommandFlags flags = CommandFlags.None) =>
Inner.SortedSetPopAsync(ToInner(keys), count, order, flags);

public Task<long> StreamAcknowledgeAsync(RedisKey key, RedisValue groupName, RedisValue messageId, CommandFlags flags = CommandFlags.None) =>
Inner.StreamAcknowledgeAsync(ToInner(key), groupName, messageId, flags);

Expand Down
35 changes: 35 additions & 0 deletions src/StackExchange.Redis/ListPopResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;

namespace StackExchange.Redis;

/// <summary>
/// A contiguous portion of a redis list.
/// </summary>
public readonly struct ListPopResult
{
/// <summary>
/// A null ListPopResult, indicating no results.
/// </summary>
public static ListPopResult Null { get; } = new ListPopResult(RedisKey.Null, Array.Empty<RedisValue>());

/// <summary>
/// Whether this object is null/empty.
/// </summary>
public bool IsNull => Key.IsNull && Values == Array.Empty<RedisValue>();

/// <summary>
/// The key of the list that this set of entries came form.
/// </summary>
public RedisKey Key { get; }

/// <summary>
/// The values from the list.
/// </summary>
public RedisValue[] Values { get; }

internal ListPopResult(RedisKey key, RedisValue[] values)
{
Key = key;
Values = values;
}
}
Loading