@@ -9,6 +9,20 @@ namespace LightningDB;
9
9
/// <summary>
10
10
/// Represents a cursor used to navigate and manipulate records within a database in the context of a transaction.
11
11
/// </summary>
12
+ /// <remarks>
13
+ /// A cursor is associated with a specific transaction and database and cannot be used when its database handle
14
+ /// is closed or when its transaction has ended (except with <see cref="LightningTransaction.Renew"/>).
15
+ ///
16
+ /// Cursor lifecycle management:
17
+ /// - A cursor in a write-transaction can be closed before its transaction ends, and will otherwise be closed when its transaction ends.
18
+ /// - A cursor in a read-only transaction must be closed explicitly, before or after its transaction ends.
19
+ /// - It can be reused with <see cref="LightningTransaction.Renew"/> before finally closing it.
20
+ ///
21
+ /// Cursors cannot span threads - a cursor handle may only be used by a single thread.
22
+ ///
23
+ /// A cursor maintains a position in the database and can be used for navigation and
24
+ /// for operations like insertion, deletion, or retrieval of database records.
25
+ /// </remarks>
12
26
public class LightningCursor : IDisposable
13
27
{
14
28
private nint _handle ;
@@ -51,7 +65,7 @@ public MDBResultCode Set(byte[] key)
51
65
{
52
66
return Get ( CursorOperation . Set , key ) . resultCode ;
53
67
}
54
-
68
+
55
69
/// <summary>
56
70
/// Position at specified key, if key is not found index will be positioned to closest match.
57
71
/// </summary>
@@ -71,7 +85,7 @@ public MDBResultCode Set(ReadOnlySpan<byte> key)
71
85
{
72
86
return Get ( CursorOperation . SetKey , key ) ;
73
87
}
74
-
88
+
75
89
/// <summary>
76
90
/// Moves to the key and populates Current with the values stored.
77
91
/// </summary>
@@ -92,7 +106,7 @@ public MDBResultCode GetBoth(byte[] key, byte[] value)
92
106
{
93
107
return Get ( CursorOperation . GetBoth , key , value ) . resultCode ;
94
108
}
95
-
109
+
96
110
/// <summary>
97
111
/// Position at key/data pair. Only for MDB_DUPSORT
98
112
/// </summary>
@@ -114,7 +128,7 @@ public MDBResultCode GetBothRange(byte[] key, byte[] value)
114
128
{
115
129
return Get ( CursorOperation . GetBothRange , key , value ) . resultCode ;
116
130
}
117
-
131
+
118
132
/// <summary>
119
133
/// position at key, nearest data. Only for MDB_DUPSORT
120
134
/// </summary>
@@ -135,7 +149,7 @@ public MDBResultCode SetRange(byte[] key)
135
149
{
136
150
return Get ( CursorOperation . SetRange , key ) . resultCode ;
137
151
}
138
-
152
+
139
153
/// <summary>
140
154
/// Position at first key greater than or equal to specified key.
141
155
/// </summary>
@@ -254,7 +268,7 @@ public MDBResultCode SetRange(ReadOnlySpan<byte> key)
254
268
{
255
269
return Get ( CursorOperation . PreviousNoDuplicate ) ;
256
270
}
257
-
271
+
258
272
private ( MDBResultCode resultCode , MDBValue key , MDBValue value ) Get ( CursorOperation operation )
259
273
{
260
274
var mdbKey = new MDBValue ( ) ;
@@ -300,7 +314,7 @@ private unsafe (MDBResultCode resultCode, MDBValue key, MDBValue value) Get(Curs
300
314
/// Store by cursor.
301
315
/// This function stores key/data pairs into the database. The cursor is positioned at the new item, or on failure usually near it.
302
316
/// Note: Earlier documentation incorrectly said errors would leave the state of the cursor unchanged.
303
- /// If the function fails for any reason, the state of the cursor will be unchanged.
317
+ /// If the function fails for any reason, the state of the cursor will be unchanged.
304
318
/// If the function succeeds and an item is inserted into the database, the cursor is always positioned to refer to the newly inserted item.
305
319
/// </summary>
306
320
/// <param name="key">The key operated on.</param>
@@ -325,7 +339,7 @@ public MDBResultCode Put(byte[] key, byte[] value, CursorPutOptions options)
325
339
/// Store by cursor.
326
340
/// This function stores key/data pairs into the database. The cursor is positioned at the new item, or on failure usually near it.
327
341
/// Note: Earlier documentation incorrectly said errors would leave the state of the cursor unchanged.
328
- /// If the function fails for any reason, the state of the cursor will be unchanged.
342
+ /// If the function fails for any reason, the state of the cursor will be unchanged.
329
343
/// If the function succeeds and an item is inserted into the database, the cursor is always positioned to refer to the newly inserted item.
330
344
/// </summary>
331
345
/// <param name="key">The key operated on.</param>
@@ -354,8 +368,8 @@ public unsafe MDBResultCode Put(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value
354
368
355
369
/// <summary>
356
370
/// Store by cursor.
357
- /// This function stores key/data pairs into the database.
358
- /// If the function fails for any reason, the state of the cursor will be unchanged.
371
+ /// This function stores key/data pairs into the database.
372
+ /// If the function fails for any reason, the state of the cursor will be unchanged.
359
373
/// If the function succeeds and an item is inserted into the database, the cursor is always positioned to refer to the newly inserted item.
360
374
/// </summary>
361
375
/// <param name="key">The key operated on.</param>
@@ -368,7 +382,7 @@ public unsafe MDBResultCode Put(byte[] key, byte[][] values)
368
382
var overallLength = values . Sum ( arr => arr . Length ) ; //probably allocates but boy is it handy...
369
383
370
384
371
- //the idea here is to gain some perf by stackallocating the buffer to
385
+ //the idea here is to gain some perf by stackallocating the buffer to
372
386
//hold the contiguous keys
373
387
if ( overallLength < StackAllocateLimit )
374
388
{
@@ -384,7 +398,7 @@ public unsafe MDBResultCode Put(byte[] key, byte[][] values)
384
398
}
385
399
386
400
//these local methods could be made static, but the compiler will emit these closures
387
- //as structs with very little overhead. Also static local functions isn't available
401
+ //as structs with very little overhead. Also static local functions isn't available
388
402
//until C# 8 so I can't use it anyway...
389
403
MDBResultCode InnerPutMultiple ( Span < byte > contiguousValuesBuffer )
390
404
{
@@ -415,7 +429,7 @@ void FlattenInfo(Span<byte> targetBuffer)
415
429
}
416
430
}
417
431
418
- int GetSize ( )
432
+ int GetSize ( )
419
433
{
420
434
if ( values . Length == 0 || values [ 0 ] == null || values [ 0 ] . Length == 0 )
421
435
return 0 ;
@@ -465,8 +479,8 @@ public MDBResultCode Delete()
465
479
466
480
/// <summary>
467
481
/// Renew a cursor handle.
468
- /// Cursors are associated with a specific transaction and database and may not span threads.
469
- /// Cursors that are only used in read-only transactions may be re-used, to avoid unnecessary malloc/free overhead.
482
+ /// Cursors are associated with a specific transaction and database and may not span threads.
483
+ /// Cursors that are only used in read-only transactions may be re-used, to avoid unnecessary malloc/free overhead.
470
484
/// The cursor may be associated with a new read-only transaction, and referencing the same database handle as it was created with.
471
485
/// </summary>
472
486
/// <returns>Returns <see cref="MDBResultCode"/></returns>
@@ -477,8 +491,8 @@ public MDBResultCode Renew()
477
491
478
492
/// <summary>
479
493
/// Renew a cursor handle.
480
- /// Cursors are associated with a specific transaction and database and may not span threads.
481
- /// Cursors that are only used in read-only transactions may be re-used, to avoid unnecessary malloc/free overhead.
494
+ /// Cursors are associated with a specific transaction and database and may not span threads.
495
+ /// Cursors that are only used in read-only transactions may be re-used, to avoid unnecessary malloc/free overhead.
482
496
/// The cursor may be associated with a new read-only transaction, and referencing the same database handle as it was created with.
483
497
/// </summary>
484
498
/// <param name="txn">Transaction to renew in.</param>
@@ -493,11 +507,11 @@ public MDBResultCode Renew(LightningTransaction txn)
493
507
494
508
return mdb_cursor_renew ( txn . _handle , _handle ) ;
495
509
}
496
-
510
+
497
511
/// <summary>
498
512
/// Return count of duplicates for current key.
499
- ///
500
- /// This call is only valid on databases that support sorted duplicate data items DatabaseOpenFlags.DuplicatesFixed.
513
+ ///
514
+ /// This call is only valid on databases that support sorted duplicate data items DatabaseOpenFlags.DuplicatesFixed.
501
515
/// </summary>
502
516
/// <param name="value">Output parameter where the duplicate count will be stored.</param>
503
517
/// <returns>Returns <see cref="MDBResultCode"/></returns>
@@ -534,7 +548,7 @@ private void Dispose(bool disposing)
534
548
{
535
549
throw new InvalidOperationException ( "The LightningCursor in a read-only transaction must be disposed explicitly." ) ;
536
550
}
537
-
551
+
538
552
if ( ShouldCloseCursor ( ) )
539
553
{
540
554
mdb_cursor_close ( _handle ) ;
@@ -559,4 +573,4 @@ public void Dispose()
559
573
{
560
574
Dispose ( false ) ;
561
575
}
562
- }
576
+ }
0 commit comments