Skip to content

Commit d7d52fd

Browse files
TedHartMSbadrishc
andauthored
Add a quick check for tail address match during iteration (#677)
* Add a quick check for tail address match during iteration * Add struct wrapper around cursor scan functions Add a BDN test (not yet working) * Fix the iterator BDN * fix formatting --------- Co-authored-by: Badrish Chandramouli <[email protected]>
1 parent 96b75ec commit d7d52fd

File tree

11 files changed

+268
-78
lines changed

11 files changed

+268
-78
lines changed

libs/cluster/Session/ClusterCommands.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ private int CountKeysInSessionStore(int slot)
2020
{
2121
ClusterKeyIterationFunctions.MainStoreCountKeys iterFuncs = new(slot);
2222
_ = basicGarnetApi.IterateMainStore(ref iterFuncs);
23-
return iterFuncs.keyCount;
23+
return iterFuncs.KeyCount;
2424
}
2525

2626
private int CountKeysInObjectStore(int slot)
@@ -29,7 +29,7 @@ private int CountKeysInObjectStore(int slot)
2929
{
3030
ClusterKeyIterationFunctions.ObjectStoreCountKeys iterFuncs = new(slot);
3131
_ = basicGarnetApi.IterateObjectStore(ref iterFuncs);
32-
return iterFuncs.keyCount;
32+
return iterFuncs.KeyCount;
3333
}
3434
return 0;
3535
}

libs/cluster/Session/ClusterKeyIterationFunctions.cs

+23-10
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,30 @@ internal sealed unsafe partial class ClusterSession : IClusterSession
1313
{
1414
internal static class ClusterKeyIterationFunctions
1515
{
16+
internal class KeyIterationInfo
17+
{
18+
// This must be a class as it is passed through pending IO operations, so it is wrapped by higher structures for inlining as a generic type arg.
19+
internal int keyCount;
20+
internal readonly int slot;
21+
22+
internal KeyIterationInfo(int slot) => this.slot = slot;
23+
}
24+
1625
internal sealed class MainStoreCountKeys : IScanIteratorFunctions<SpanByte, SpanByte>
1726
{
27+
private readonly KeyIterationInfo info;
1828
// This must be a class as it is passed through pending IO operations
19-
internal int keyCount;
20-
readonly int slot;
2129

22-
internal MainStoreCountKeys(int slot) => this.slot = slot;
30+
internal int KeyCount { get => info.keyCount; set => info.keyCount = value; }
31+
internal int Slot => info.slot;
32+
33+
internal MainStoreCountKeys(int slot) => info = new(slot);
2334

2435
public bool SingleReader(ref SpanByte key, ref SpanByte value, RecordMetadata recordMetadata, long numberOfRecords, out CursorRecordResult cursorRecordResult)
2536
{
2637
cursorRecordResult = CursorRecordResult.Accept; // default; not used here
27-
if (HashSlotUtils.HashSlot(ref key) == slot && !Expired(ref value))
28-
keyCount++;
38+
if (HashSlotUtils.HashSlot(ref key) == Slot && !Expired(ref value))
39+
KeyCount++;
2940
return true;
3041
}
3142
public bool ConcurrentReader(ref SpanByte key, ref SpanByte value, RecordMetadata recordMetadata, long numberOfRecords, out CursorRecordResult cursorRecordResult)
@@ -37,19 +48,21 @@ public void OnException(Exception exception, long numberOfRecords) { }
3748

3849
internal sealed class ObjectStoreCountKeys : IScanIteratorFunctions<byte[], IGarnetObject>
3950
{
51+
private readonly KeyIterationInfo info;
4052
// This must be a class as it is passed through pending IO operations
41-
internal int keyCount;
42-
readonly int slot;
4353

44-
internal ObjectStoreCountKeys(int slot) => this.slot = slot;
54+
internal int KeyCount { get => info.keyCount; set => info.keyCount = value; }
55+
internal int Slot => info.slot;
56+
57+
internal ObjectStoreCountKeys(int slot) => info = new(slot);
4558

4659
public bool SingleReader(ref byte[] key, ref IGarnetObject value, RecordMetadata recordMetadata, long numberOfRecords, out CursorRecordResult cursorRecordResult)
4760
{
4861
cursorRecordResult = CursorRecordResult.Accept; // default; not used here , out CursorRecordResult cursorRecordResult
4962
fixed (byte* keyPtr = key)
5063
{
51-
if (HashSlotUtils.HashSlot(keyPtr, key.Length) == slot && !Expired(ref value))
52-
keyCount++;
64+
if (HashSlotUtils.HashSlot(keyPtr, key.Length) == Slot && !Expired(ref value))
65+
KeyCount++;
5366
}
5467
return true;
5568
}

libs/server/Storage/Session/Common/ArrayKeyIterationFunctions.cs

+52-31
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Garnet.server
1010
{
1111
sealed partial class StorageSession : IDisposable
1212
{
13-
// These are classes so instantiate once and re-initialize
13+
// These contain classes so instantiate once and re-initialize
1414
private ArrayKeyIterationFunctions.MainStoreGetDBSize mainStoreDbSizeFuncs;
1515
private ArrayKeyIterationFunctions.ObjectStoreGetDBSize objectStoreDbSizeFuncs;
1616

@@ -180,48 +180,61 @@ internal int DbSize()
180180
mainStoreDbSizeFuncs.Initialize();
181181
long cursor = 0;
182182
basicContext.Session.ScanCursor(ref cursor, long.MaxValue, mainStoreDbSizeFuncs);
183-
int count = mainStoreDbSizeFuncs.count;
183+
int count = mainStoreDbSizeFuncs.Count;
184184
if (objectStoreBasicContext.Session != null)
185185
{
186186
objectStoreDbSizeFuncs ??= new();
187187
objectStoreDbSizeFuncs.Initialize();
188188
cursor = 0;
189189
objectStoreBasicContext.Session.ScanCursor(ref cursor, long.MaxValue, objectStoreDbSizeFuncs);
190-
count += objectStoreDbSizeFuncs.count;
190+
count += objectStoreDbSizeFuncs.Count;
191191
}
192192

193193
return count;
194194
}
195195

196196
internal static unsafe class ArrayKeyIterationFunctions
197197
{
198-
internal sealed class MainStoreGetDBKeys : IScanIteratorFunctions<SpanByte, SpanByte>
198+
internal class GetDBKeysInfo
199199
{
200-
List<byte[]> keys;
201-
byte* patternB;
202-
int patternLength;
200+
// This must be a class as it is passed through pending IO operations, so it is wrapped by higher structures for inlining as a generic type arg.
201+
internal List<byte[]> keys;
202+
internal byte* patternB;
203+
internal int patternLength;
204+
internal Type matchType;
203205

204-
internal void Initialize(List<byte[]> keys, byte* patternB, int length)
206+
internal void Initialize(List<byte[]> keys, byte* patternB, int length, Type matchType = null)
205207
{
206208
this.keys = keys;
207209
this.patternB = patternB;
208210
this.patternLength = length;
211+
this.matchType = matchType;
209212
}
213+
}
214+
215+
internal sealed class MainStoreGetDBKeys : IScanIteratorFunctions<SpanByte, SpanByte>
216+
{
217+
private readonly GetDBKeysInfo info;
218+
219+
internal MainStoreGetDBKeys() => info = new();
220+
221+
internal void Initialize(List<byte[]> keys, byte* patternB, int length)
222+
=> info.Initialize(keys, patternB, length);
210223

211224
public bool SingleReader(ref SpanByte key, ref SpanByte value, RecordMetadata recordMetadata, long numberOfRecords, out CursorRecordResult cursorRecordResult)
212225
=> ConcurrentReader(ref key, ref value, recordMetadata, numberOfRecords, out cursorRecordResult);
213226

214227
public bool ConcurrentReader(ref SpanByte key, ref SpanByte value, RecordMetadata recordMetadata, long numberOfRecords, out CursorRecordResult cursorRecordResult)
215228
{
216-
if ((patternB != null && !GlobUtils.Match(patternB, patternLength, key.ToPointer(), key.Length, true))
229+
if ((info.patternB != null && !GlobUtils.Match(info.patternB, info.patternLength, key.ToPointer(), key.Length, true))
217230
|| (value.MetadataSize != 0 && MainSessionFunctions.CheckExpiry(ref value)))
218231
{
219232
cursorRecordResult = CursorRecordResult.Skip;
220233
}
221234
else
222235
{
223236
cursorRecordResult = CursorRecordResult.Accept;
224-
keys.Add(key.ToByteArray());
237+
info.keys.Add(key.ToByteArray());
225238
}
226239
return true;
227240
}
@@ -233,18 +246,12 @@ public void OnException(Exception exception, long numberOfRecords) { }
233246

234247
internal sealed class ObjectStoreGetDBKeys : IScanIteratorFunctions<byte[], IGarnetObject>
235248
{
236-
List<byte[]> keys;
237-
byte* patternB;
238-
int patternLength;
239-
private Type matchType;
249+
private readonly GetDBKeysInfo info;
250+
251+
internal ObjectStoreGetDBKeys() => info = new();
240252

241253
internal void Initialize(List<byte[]> keys, byte* patternB, int length, Type matchType = null)
242-
{
243-
this.keys = keys;
244-
this.patternB = patternB;
245-
this.patternLength = length;
246-
this.matchType = matchType;
247-
}
254+
=> info.Initialize(keys, patternB, length, matchType);
248255

249256
public bool SingleReader(ref byte[] key, ref IGarnetObject value, RecordMetadata recordMetadata, long numberOfRecords, out CursorRecordResult cursorRecordResult)
250257
=> ConcurrentReader(ref key, ref value, recordMetadata, numberOfRecords, out cursorRecordResult);
@@ -257,25 +264,25 @@ public bool ConcurrentReader(ref byte[] key, ref IGarnetObject value, RecordMeta
257264
return true;
258265
}
259266

260-
if (patternB != null)
267+
if (info.patternB != null)
261268
{
262269
fixed (byte* keyPtr = key)
263270
{
264-
if (!GlobUtils.Match(patternB, patternLength, keyPtr, key.Length, true))
271+
if (!GlobUtils.Match(info.patternB, info.patternLength, keyPtr, key.Length, true))
265272
{
266273
cursorRecordResult = CursorRecordResult.Skip;
267274
return true;
268275
}
269276
}
270277
}
271278

272-
if (matchType != null && value.GetType() != matchType)
279+
if (info.matchType != null && value.GetType() != info.matchType)
273280
{
274281
cursorRecordResult = CursorRecordResult.Skip;
275282
return true;
276283
}
277284

278-
keys.Add(key);
285+
info.keys.Add(key);
279286
cursorRecordResult = CursorRecordResult.Accept;
280287
return true;
281288
}
@@ -285,12 +292,23 @@ public void OnStop(bool completed, long numberOfRecords) { }
285292
public void OnException(Exception exception, long numberOfRecords) { }
286293
}
287294

288-
internal sealed class MainStoreGetDBSize : IScanIteratorFunctions<SpanByte, SpanByte>
295+
internal class GetDBSizeInfo
289296
{
290-
// This must be a class as it is passed through pending IO operations
297+
// This must be a class as it is passed through pending IO operations, so it is wrapped by higher structures for inlining as a generic type arg.
291298
internal int count;
292299

293300
internal void Initialize() => count = 0;
301+
}
302+
303+
internal sealed class MainStoreGetDBSize : IScanIteratorFunctions<SpanByte, SpanByte>
304+
{
305+
private readonly GetDBSizeInfo info;
306+
307+
internal int Count => info.count;
308+
309+
internal MainStoreGetDBSize() => info = new();
310+
311+
internal void Initialize() => info.Initialize();
294312

295313
public bool SingleReader(ref SpanByte key, ref SpanByte value, RecordMetadata recordMetadata, long numberOfRecords, out CursorRecordResult cursorRecordResult)
296314
{
@@ -299,7 +317,7 @@ public bool SingleReader(ref SpanByte key, ref SpanByte value, RecordMetadata re
299317
else
300318
{
301319
cursorRecordResult = CursorRecordResult.Accept;
302-
++count;
320+
++info.count;
303321
}
304322
return true;
305323
}
@@ -312,10 +330,13 @@ public void OnException(Exception exception, long numberOfRecords) { }
312330

313331
internal sealed class ObjectStoreGetDBSize : IScanIteratorFunctions<byte[], IGarnetObject>
314332
{
315-
// This must be a class as it is passed through pending IO operations
316-
internal int count;
333+
private readonly GetDBSizeInfo info;
317334

318-
internal void Initialize() => count = 0;
335+
internal int Count => info.count;
336+
337+
internal ObjectStoreGetDBSize() => info = new();
338+
339+
internal void Initialize() => info.Initialize();
319340

320341
public bool SingleReader(ref byte[] key, ref IGarnetObject value, RecordMetadata recordMetadata, long numberOfRecords, out CursorRecordResult cursorRecordResult)
321342
{
@@ -324,7 +345,7 @@ public bool SingleReader(ref byte[] key, ref IGarnetObject value, RecordMetadata
324345
else
325346
{
326347
cursorRecordResult = CursorRecordResult.Accept;
327-
++count;
348+
++info.count;
328349
}
329350
return true;
330351
}

libs/storage/Tsavorite/cs/benchmark/BDN-Tsavorite.Benchmark/BenchmarkDotNetTestsApp.cs

+14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ public class BenchmarkDotNetTestsApp
1111

1212
public static void Main(string[] args)
1313
{
14+
// Check for debugging a test
15+
if (args[0].ToLower() == "cursor")
16+
{
17+
var test = new IterationTests
18+
{
19+
FlushAndEvict = true
20+
};
21+
test.SetupPopulatedStore();
22+
test.Cursor();
23+
test.TearDown();
24+
return;
25+
}
26+
27+
// Do regular invocation.
1428
BenchmarkSwitcher.FromAssembly(typeof(BenchmarkDotNetTestsApp).Assembly).Run(args);
1529
}
1630
}

0 commit comments

Comments
 (0)