Skip to content

Commit 7e29c3a

Browse files
[Compatibility] Added NOVALUE option for HSCAN (#701)
* Added NOVALUE option for HSCAN * Review comment fix * Fixed test case faliure --------- Co-authored-by: Badrish Chandramouli <[email protected]>
1 parent cf21bd4 commit 7e29c3a

File tree

15 files changed

+45
-20
lines changed

15 files changed

+45
-20
lines changed

Directory.Packages.props

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
2222
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.0.1" />
2323
<PackageVersion Include="Microsoft.IdentityModel.Validators" Version="8.0.1" />
24-
<PackageVersion Include="StackExchange.Redis" Version="2.8.0" />
24+
<PackageVersion Include="StackExchange.Redis" Version="2.8.16" />
2525
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.0.1" />
2626
<PackageVersion Include="System.Interactive.Async" Version="6.0.1" />
2727
<PackageVersion Include="System.Text.Json" Version="8.0.5" />

libs/server/Custom/CustomObjectBase.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public sealed override unsafe bool Operate(ref ObjectInput input, ref SpanByteAn
7878
// Scan Command
7979
case RespCommand.COSCAN:
8080
if (ObjectUtils.ReadScanInput(ref input, ref output, out var cursorInput, out var pattern,
81-
out var patternLength, out var limitCount, out var error))
81+
out var patternLength, out var limitCount, out bool _, out var error))
8282
{
8383
Scan(cursorInput, out var items, out var cursorOutput, count: limitCount, pattern: pattern,
8484
patternLength: patternLength);

libs/server/Objects/Hash/HashObject.cs

+12-6
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,10 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory
172172
break;
173173
case HashOperation.HSCAN:
174174
if (ObjectUtils.ReadScanInput(ref input, ref output, out var cursorInput, out var pattern,
175-
out var patternLength, out var limitCount, out var error))
175+
out var patternLength, out var limitCount, out bool isNoValue, out var error))
176176
{
177177
Scan(cursorInput, out var items, out var cursorOutput, count: limitCount, pattern: pattern,
178-
patternLength: patternLength);
178+
patternLength: patternLength, isNoValue);
179179
ObjectUtils.WriteScanOutput(items, cursorOutput, ref output);
180180
}
181181
else
@@ -203,7 +203,7 @@ private void UpdateSize(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value, bool a
203203
}
204204

205205
/// <inheritdoc />
206-
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0)
206+
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0, bool isNoValue = false)
207207
{
208208
cursor = start;
209209
items = new List<byte[]>();
@@ -215,7 +215,7 @@ public override unsafe void Scan(long start, out List<byte[]> items, out long cu
215215
}
216216

217217
// Hashset has key and value, so count is multiplied by 2
218-
count *= 2;
218+
count = isNoValue ? count : count * 2;
219219
int index = 0;
220220
foreach (var item in hash)
221221
{
@@ -228,7 +228,10 @@ public override unsafe void Scan(long start, out List<byte[]> items, out long cu
228228
if (patternLength == 0)
229229
{
230230
items.Add(item.Key);
231-
items.Add(item.Value);
231+
if (!isNoValue)
232+
{
233+
items.Add(item.Value);
234+
}
232235
}
233236
else
234237
{
@@ -237,7 +240,10 @@ public override unsafe void Scan(long start, out List<byte[]> items, out long cu
237240
if (GlobUtils.Match(pattern, patternLength, keyPtr, item.Key.Length))
238241
{
239242
items.Add(item.Key);
240-
items.Add(item.Value);
243+
if (!isNoValue)
244+
{
245+
items.Add(item.Value);
246+
}
241247
}
242248
}
243249
}

libs/server/Objects/List/ListObject.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ internal void UpdateSize(byte[] item, bool add = true)
203203
}
204204

205205
/// <inheritdoc />
206-
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0)
206+
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0, bool isNoValue = false)
207207
{
208208
throw new NotImplementedException("For scan items in a list use LRANGE command");
209209
}

libs/server/Objects/ObjectUtils.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public static unsafe void ReallocateOutput(ref SpanByteAndMemory output, ref boo
4949
/// <param name="error"></param>
5050
/// <returns></returns>
5151
public static unsafe bool ReadScanInput(ref ObjectInput input, ref SpanByteAndMemory output,
52-
out int cursorInput, out byte* pattern, out int patternLength, out int countInInput, out ReadOnlySpan<byte> error)
52+
out int cursorInput, out byte* pattern, out int patternLength, out int countInInput, out bool isNoValue, out ReadOnlySpan<byte> error)
5353
{
5454
var currTokenIdx = input.parseStateStartIdx;
5555

@@ -66,6 +66,7 @@ public static unsafe bool ReadScanInput(ref ObjectInput input, ref SpanByteAndMe
6666
countInInput = 10;
6767

6868
error = default;
69+
isNoValue = false;
6970

7071
while (currTokenIdx < input.parseState.Count)
7172
{
@@ -90,6 +91,10 @@ public static unsafe bool ReadScanInput(ref ObjectInput input, ref SpanByteAndMe
9091
if (countInInput > limitCountInOutput)
9192
countInInput = limitCountInOutput;
9293
}
94+
else if (sbParam.SequenceEqual(CmdStrings.NOVALUES) || sbParam.SequenceEqual(CmdStrings.novalues))
95+
{
96+
isNoValue = true;
97+
}
9398
}
9499

95100
return true;

libs/server/Objects/Set/SetObject.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory
143143
break;
144144
case SetOperation.SSCAN:
145145
if (ObjectUtils.ReadScanInput(ref input, ref output, out var cursorInput, out var pattern,
146-
out var patternLength, out var limitCount, out var error))
146+
out var patternLength, out var limitCount, out bool _, out var error))
147147
{
148148
Scan(cursorInput, out var items, out var cursorOutput, count: limitCount, pattern: pattern,
149149
patternLength: patternLength);
@@ -172,7 +172,7 @@ internal void UpdateSize(ReadOnlySpan<byte> item, bool add = true)
172172
}
173173

174174
/// <inheritdoc />
175-
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0)
175+
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0, bool isNoValue = false)
176176
{
177177
cursor = start;
178178
items = new List<byte[]>();

libs/server/Objects/SortedSet/SortedSetObject.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory
304304
break;
305305
case SortedSetOperation.ZSCAN:
306306
if (ObjectUtils.ReadScanInput(ref input, ref output, out var cursorInput, out var pattern,
307-
out var patternLength, out var limitCount, out var error))
307+
out var patternLength, out var limitCount, out var _, out var error))
308308
{
309309
Scan(cursorInput, out var items, out var cursorOutput, count: limitCount, pattern: pattern,
310310
patternLength: patternLength);
@@ -326,7 +326,7 @@ public override unsafe bool Operate(ref ObjectInput input, ref SpanByteAndMemory
326326
}
327327

328328
/// <inheritdoc />
329-
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0)
329+
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0, bool isNoValue = false)
330330
{
331331
cursor = start;
332332
items = new List<byte[]>();

libs/server/Objects/Types/GarnetObjectBase.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,6 @@ private bool MakeTransition(SerializationPhase expectedPhase, SerializationPhase
146146
/// <param name="pattern">A patter used to match the members of the collection</param>
147147
/// <param name="patternLength">The number of characters in the pattern</param>
148148
/// <returns></returns>
149-
public abstract unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0);
149+
public abstract unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0, bool isNoValue = false);
150150
}
151151
}

libs/server/Objects/Types/IGarnetObject.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,6 @@ public interface IGarnetObject : IDisposable
5858
/// <param name="pattern">A patter used to match the members of the collection</param>
5959
/// <param name="patternLength">The number of characters in the pattern</param>
6060
/// <returns></returns>
61-
unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0);
61+
unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = default, int patternLength = 0, bool isNoValue = false);
6262
}
6363
}

libs/server/Resp/CmdStrings.cs

+2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ static partial class CmdStrings
7171
public static ReadOnlySpan<byte> match => "match"u8;
7272
public static ReadOnlySpan<byte> COUNT => "COUNT"u8;
7373
public static ReadOnlySpan<byte> count => "count"u8;
74+
public static ReadOnlySpan<byte> NOVALUES => "NOVALUES"u8;
75+
public static ReadOnlySpan<byte> novalues => "novalues"u8;
7476
public static ReadOnlySpan<byte> TYPE => "TYPE"u8;
7577
public static ReadOnlySpan<byte> type => "type"u8;
7678
public static ReadOnlySpan<byte> REGISTERCS => "REGISTERCS"u8;

main/GarnetServer/Extensions/MyDictObject.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public override void Dispose() { }
7979
/// <param name="pattern"></param>
8080
/// <param name="patternLength"></param>
8181
/// <returns></returns>
82-
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = null, int patternLength = 0)
82+
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = null, int patternLength = 0, bool isNoValue = false)
8383
{
8484
cursor = start;
8585
items = new();

playground/GarnetJSON/JsonObject.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,6 @@ public bool TryGet(string path, out string jsonString, ILogger? logger = null)
216216
}
217217

218218
/// <inheritdoc/>
219-
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = null, int patternLength = 0) => throw new NotImplementedException();
219+
public override unsafe void Scan(long start, out List<byte[]> items, out long cursor, int count = 10, byte* pattern = null, int patternLength = 0, bool isNoValue = false) => throw new NotImplementedException();
220220
}
221221
}

test/Garnet.test/RespHashTests.cs

+10
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,16 @@ public void CanDoHashScan()
413413

414414
members = db.HashScan("user:user789", "*");
415415
ClassicAssert.IsTrue(members.Count() == 5, "HSCAN with MATCH failed.");
416+
417+
var fields = db.HashScanNoValues("user:user789", "*");
418+
ClassicAssert.IsTrue(fields.Count() == 5, "HSCAN with MATCH failed.");
419+
CollectionAssert.AreEquivalent(new[] { "email", "email1", "email2", "email3", "age" }, fields.Select(f => f.ToString()));
420+
421+
RedisResult result = db.Execute("HSCAN", "user:user789", "0", "MATCH", "*", "COUNT", "2", "NOVALUES");
422+
ClassicAssert.IsTrue(result.Length == 2);
423+
var fieldsStr = ((RedisResult[]?)result[1]).Select(x => (string)x).ToArray();
424+
ClassicAssert.IsTrue(fieldsStr.Length == 2, "HSCAN with MATCH failed.");
425+
CollectionAssert.AreEquivalent(new[] { "email", "email1" }, fieldsStr);
416426
}
417427

418428

website/docs/commands/api-compatibility.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ Note that this list is subject to change as we continue to expand our API comman
180180
| | HPEXPIRETIME || |
181181
| | HPTTL || |
182182
| | [HRANDFIELD](data-structures.md#hrandfield) || |
183-
| | [HSCAN](data-structures.md#hscan) || `NOVALUES` flag not yet implemented |
183+
| | [HSCAN](data-structures.md#hscan) || |
184184
| | [HSET](data-structures.md#hset) || |
185185
| | [HSETNX](data-structures.md#hsetnx) || |
186186
| | [HSTRLEN](data-structures.md#hstrlen) || |

website/docs/commands/data-structures.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,15 @@ The optional WITHVALUES modifier changes the reply so it includes the respective
159159
#### Syntax
160160
161161
```bash
162-
HSCAN key cursor [MATCH pattern] [COUNT count]
162+
HSCAN key cursor [MATCH pattern] [COUNT count] [NOVALUES]
163163
```
164164
165165
Iterates over the fields and values of a hash stored at a given **key**. Same as [SSCAN](#sscan) and [ZSCAN](#zscan) commands, **HSCAN** is used in order to incrementally iterate over the elements of the hash set*.
166166
167167
The **match** parameter allows to apply a filter to elements after they have been retrieved from the collection. The **count** option sets a limit to the maximum number of items returned from the server to this command. This limit is also set in conjunction with the object-scan-count-limit of the global server settings.
168168
169+
You can use the **NOVALUES** option to make Redis return only the keys in the hash table without their corresponding values
170+
169171
---
170172
171173
### HSET

0 commit comments

Comments
 (0)