Skip to content

Commit 2ccce08

Browse files
committed
Add initial support for fdb_transaction_get_versionstamp and add SetStampedKey() / SetStampedValue() mutations
1 parent 8192bb7 commit 2ccce08

File tree

12 files changed

+179
-2
lines changed

12 files changed

+179
-2
lines changed

FoundationDB.Client/Core/IFdbTransactionHandler.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ public interface IFdbTransactionHandler : IDisposable
6161
/// </remarks>
6262
long GetCommittedVersion();
6363

64+
/// <summary>Returns the <see cref="VersionStamp"/> which was used by versionstamps operations in this transaction.</summary>
65+
Task<VersionStamp> GetVersionStampAsync(CancellationToken ct);
66+
6467
/// <summary>Sets the snapshot read version used by a transaction. This is not needed in simple cases.</summary>
6568
/// <param name="version">Read version to use in this transaction</param>
6669
/// <remarks>

FoundationDB.Client/FdbMutationType.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,13 @@ public enum FdbMutationType
9191
/// If ``param`` is shorter than the existing value in the database, the existing value is truncated to match the length of ``param``.
9292
/// The smaller of the two values is then stored in the database.
9393
/// </summary>
94-
Min = 13
94+
Min = 13,
95+
96+
//TODO: XML Comments!
97+
VersionStampedKey = 14,
98+
99+
//TODO: XML Comments!
100+
VersionStampedValue = 15,
95101

96102
}
97103

FoundationDB.Client/FdbTransaction.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,19 @@ public void SetReadVersion(long version)
284284
m_handler.SetReadVersion(version);
285285
}
286286

287+
/// <summary>Returns the <see cref="VersionStamp"/> which was used by versionstamps operations in this transaction.</summary>
288+
/// <remarks>
289+
/// The Task will be ready only after the successful completion of a call to <see cref="CommitAsync"/> on this transaction.
290+
/// Read-only transactions do not modify the database when committed and will result in the Task completing with an error.
291+
/// Keep in mind that a transaction which reads keys and then sets them to their current values may be optimized to a read-only transaction.
292+
/// </remarks>
293+
public Task<VersionStamp> GetVersionStampAsync()
294+
{
295+
EnsureNotFailedOrDisposed();
296+
297+
return m_handler.GetVersionStampAsync(m_cancellation);
298+
}
299+
287300
#endregion
288301

289302
#region Get...
@@ -513,6 +526,23 @@ private static void EnsureMutationTypeIsSupported(FdbMutationType mutation, int
513526
return;
514527
}
515528

529+
if (mutation == FdbMutationType.VersionStampedKey || mutation == FdbMutationType.VersionStampedValue)
530+
{
531+
if (selectedApiVersion < 400)
532+
{
533+
if (Fdb.GetMaxApiVersion() >= 400)
534+
{
535+
throw new FdbException(FdbError.InvalidMutationType, "Atomic mutations for VersionStamps are only supported starting from API level 400. You need to select API level 400 or more at the start of your process.");
536+
}
537+
else
538+
{
539+
throw new FdbException(FdbError.InvalidMutationType, "Atomic mutations Max and Min are only supported starting from client version 4.x. You need to update the version of the client, and select API level 400 or more at the start of your process..");
540+
}
541+
}
542+
// ok!
543+
return;
544+
}
545+
516546
// this could be a new mutation type, or an invalid value.
517547
throw new FdbException(FdbError.InvalidMutationType, "An invalid mutation type was issued. If you are attempting to call a new mutation type, you will need to update the version of this assembly, and select the latest API level.");
518548
}

FoundationDB.Client/FdbTransactionExtensions.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,22 @@ public static void AtomicMin([NotNull] this IFdbTransaction trans, Slice key, Sl
425425
trans.Atomic(key, value, FdbMutationType.Min);
426426
}
427427

428+
//TODO: XML Comments!
429+
public static void SetVersionStampedKey([NotNull] this IFdbTransaction trans, Slice key, Slice value)
430+
{
431+
Contract.NotNull(trans, nameof(trans));
432+
433+
trans.Atomic(key, value, FdbMutationType.VersionStampedKey);
434+
}
435+
436+
//TODO: XML Comments!
437+
public static void SetVersionStampedValue([NotNull] this IFdbTransaction trans, Slice key, Slice value)
438+
{
439+
Contract.NotNull(trans, nameof(trans));
440+
441+
trans.Atomic(key, value, FdbMutationType.VersionStampedValue);
442+
}
443+
428444
#endregion
429445

430446
#region GetRange...

FoundationDB.Client/Filters/FdbTransactionFilter.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@ public virtual long GetCommittedVersion()
251251
return m_transaction.GetCommittedVersion();
252252
}
253253

254+
public virtual Task<VersionStamp> GetVersionStampAsync()
255+
{
256+
ThrowIfDisposed();
257+
return m_transaction.GetVersionStampAsync();
258+
}
259+
254260
public virtual void SetReadVersion(long version)
255261
{
256262
ThrowIfDisposed();

FoundationDB.Client/Filters/Logging/FdbLoggedTransaction.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,14 @@ public override Task OnErrorAsync(FdbError code)
312312
);
313313
}
314314

315+
public override Task<VersionStamp> GetVersionStampAsync()
316+
{
317+
return ExecuteAsync(
318+
new FdbTransactionLog.GetVersionStampCommand(),
319+
(tr, cmd) => tr.GetVersionStampAsync()
320+
);
321+
}
322+
315323
public override void Set(Slice key, Slice value)
316324
{
317325
Execute(

FoundationDB.Client/Filters/Logging/FdbTransactionLog.Commands.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,12 @@ public override string GetResult(KeyResolver resolver)
832832

833833
}
834834

835+
public sealed class GetVersionStampCommand : Command<VersionStamp>
836+
{
837+
public override Operation Op { get { return Operation.GetVersionStamp; } }
838+
839+
}
840+
835841
public sealed class GetReadVersionCommand : Command<long>
836842
{
837843
public override Operation Op { get { return Operation.GetReadVersion; } }

FoundationDB.Client/Filters/Logging/FdbTransactionLog.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,7 @@ public enum Operation
552552
Reset,
553553
OnError,
554554
SetOption,
555+
GetVersionStamp,
555556

556557
Log,
557558
}

FoundationDB.Client/IFdbTransaction.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ public interface IFdbTransaction : IFdbReadOnlyTransaction
112112
/// </remarks>
113113
long GetCommittedVersion();
114114

115+
/// <summary>Returns the <see cref="VersionStamp"/> which was used by versionstamps operations in this transaction.</summary>
116+
/// <remarks>
117+
/// The Task will be ready only after the successful completion of a call to <see cref="CommitAsync"/> on this transaction.
118+
/// Read-only transactions do not modify the database when committed and will result in the Task completing with an error.
119+
/// Keep in mind that a transaction which reads keys and then sets them to their current values may be optimized to a read-only transaction.
120+
/// </remarks>
121+
Task<VersionStamp> GetVersionStampAsync();
122+
115123
/// <summary>
116124
/// Watch a key for any change in the database.
117125
/// </summary>

FoundationDB.Client/Native/FdbNative.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ internal static unsafe class FdbNative
5151
private const string FDB_C_DLL = "fdb_c.dll";
5252
#endif
5353

54-
5554
/// <summary>Handle on the native FDB C API library</summary>
5655
private static readonly UnmanagedLibrary FdbCLib;
5756

@@ -169,6 +168,9 @@ public static extern void fdb_transaction_clear_range(
169168
[DllImport(FDB_C_DLL, CallingConvention = CallingConvention.Cdecl)]
170169
public static extern FdbError fdb_transaction_get_committed_version(TransactionHandle transaction, out long version);
171170

171+
[DllImport(FDB_C_DLL, CallingConvention = CallingConvention.Cdecl)]
172+
public static extern FutureHandle fdb_transaction_get_versionstamp(TransactionHandle transaction);
173+
172174
[DllImport(FDB_C_DLL, CallingConvention = CallingConvention.Cdecl)]
173175
public static extern FutureHandle fdb_transaction_watch(TransactionHandle transaction, byte* keyName, int keyNameLength);
174176

@@ -531,6 +533,16 @@ public static FutureHandle TransactionCommit(TransactionHandle transaction)
531533
return future;
532534
}
533535

536+
public static FutureHandle TransactionGetVersionStamp(TransactionHandle transaction)
537+
{
538+
var future = NativeMethods.fdb_transaction_get_versionstamp(transaction);
539+
Contract.Assert(future != null);
540+
#if DEBUG_NATIVE_CALLS
541+
Debug.WriteLine("fdb_transaction_get_versionstamp(0x" + transaction.Handle.ToString("x") + ") => 0x" + future.Handle.ToString("x"));
542+
#endif
543+
return future;
544+
}
545+
534546
public static FutureHandle TransactionWatch(TransactionHandle transaction, Slice key)
535547
{
536548
if (key.IsNullOrEmpty) throw new ArgumentException("Key cannot be null or empty", "key");
@@ -822,6 +834,27 @@ public static FdbError FutureGetStringArray(FutureHandle future, out string[] re
822834
return err;
823835
}
824836

837+
public static FdbError FutureGetVersionStamp(FutureHandle future, out VersionStamp stamp)
838+
{
839+
byte* ptr;
840+
int keyLength;
841+
var err = NativeMethods.fdb_future_get_key(future, out ptr, out keyLength);
842+
#if DEBUG_NATIVE_CALLS
843+
Debug.WriteLine("fdb_future_get_key(0x" + future.Handle.ToString("x") + ") => err=" + err + ", keyLength=" + keyLength);
844+
#endif
845+
846+
if (keyLength != 10 || ptr == null)
847+
{
848+
stamp = default;
849+
return err;
850+
}
851+
//note: we assume that this is a complete stamp read from the database.
852+
//BUGBUG: if the code serialize an incomplete stamp into a tuple, and unpacks it (logging?) it MAY be changed into a complete one!
853+
// => we could check for the 'all FF' signature, but this only works for default incomplete tokens, not custom incomplete tokens !
854+
VersionStamp.ReadUnsafe(ptr, 10, /*FLAGS_NONE*/0, out stamp);
855+
return err;
856+
}
857+
825858
public static void TransactionSet(TransactionHandle transaction, Slice key, Slice value)
826859
{
827860
fixed (byte* pKey = key.Array)

0 commit comments

Comments
 (0)