void RecoverAndTest(IDevice log) { NumClicks inputArg = default; NumClicks output = default; var f = new SimpleFunctions(); var fht2 = new FasterKV <AdId, NumClicks> (128, logSettings: new LogSettings { LogDevice = log, MutableFraction = 0.1, PageSizeBits = 10, MemorySizeBits = 13 }, checkpointSettings: new CheckpointSettings { CheckpointDir = TestUtils.MethodTestDir + "/statemachinetest" } ); fht2.Recover(); // sync, does not require session using (var s3 = fht2.ResumeSession(f, "foo", out CommitPoint lsn)) { Assert.AreEqual(numOps - 1, lsn.UntilSerialNo); // Expect checkpoint completion callback f.checkpointCallbackExpectation = 1; s3.Refresh(); // Completion callback should have been called once Assert.AreEqual(0, f.checkpointCallbackExpectation); for (var key = 0; key < numOps; key++) { var status = s3.Read(ref inputArray[key], ref inputArg, ref output, Empty.Default, s3.SerialNo); if (status.IsPending) { s3.CompletePending(true); } else { Assert.AreEqual(key, output.numClicks); } } } fht2.Dispose(); }
void RecoverAndTest(IDevice log) { NumClicks inputArg = default; NumClicks output = default; var f = new SimpleFunctions(); var fht2 = new FasterKV <AdId, NumClicks> (128, logSettings: new LogSettings { LogDevice = log, MutableFraction = 0.1, PageSizeBits = 10, MemorySizeBits = 13 }, checkpointSettings: new CheckpointSettings { CheckpointDir = TestContext.CurrentContext.TestDirectory + "\\checkpoints4", CheckPointType = CheckpointType.FoldOver } ); fht2.Recover(); // sync, does not require session using (var s3 = fht2.ResumeSession(f, "foo", out CommitPoint lsn)) { Assert.IsTrue(lsn.UntilSerialNo == numOps - 1); // Expect checkpoint completion callback f.checkpointCallbackExpectation = 1; s3.Refresh(); // Completion callback should have been called once Assert.IsTrue(f.checkpointCallbackExpectation == 0); for (var key = 0; key < numOps; key++) { var status = s3.Read(ref inputArray[key], ref inputArg, ref output, Empty.Default, s3.SerialNo); if (status == Status.PENDING) { s3.CompletePending(true); } else { Assert.IsTrue(output.numClicks == key); } } } fht2.Dispose(); }
// RMW functions public static int InitialValueLength(AdId *key, Input *input) { return(NumClicks.GetLength(default(NumClicks *))); }
public static void InitialUpdater(AdId *key, Input *input, NumClicks *value) { NumClicks.Copy(&input->numClicks, value); }
public static void ConcurrentWriter(AdId *key, NumClicks *src, NumClicks *dst) { NumClicks.AcquireWriteLock(dst); NumClicks.Copy(src, dst); NumClicks.ReleaseWriteLock(dst); }
// Upsert functions public static void SingleWriter(AdId *key, NumClicks *src, NumClicks *dst) { NumClicks.Copy(src, dst); }
public static void ConcurrentReader(AdId *key, Input *input, NumClicks *value, Output *dst) { NumClicks.AcquireReadLock(value); NumClicks.Copy(value, (NumClicks *)dst); NumClicks.ReleaseReadLock(value); }
// Read functions public static void SingleReader(AdId *key, Input *input, NumClicks *value, Output *dst) { NumClicks.Copy(value, (NumClicks *)dst); }
public void SimpleReadAndUpdateInfoTest() { checkpointManager = new DeviceLogCommitCheckpointManager(new LocalStorageNamedDeviceFactory(), new DefaultCheckpointNamingScheme(TestUtils.MethodTestDir + "/checkpoints"), false); log = Devices.CreateLogDevice(TestUtils.MethodTestDir + "/SimpleReadAndUpdateInfoTest.log", deleteOnClose: true); fht1 = new FasterKV <AdId, NumClicks>(128, logSettings: new LogSettings { LogDevice = log, MutableFraction = 0.1, MemorySizeBits = 29 }, checkpointSettings: new CheckpointSettings { CheckpointManager = checkpointManager } ); fht2 = new FasterKV <AdId, NumClicks>(128, logSettings: new LogSettings { LogDevice = log, MutableFraction = 0.1, MemorySizeBits = 29 }, checkpointSettings: new CheckpointSettings { CheckpointManager = checkpointManager } ); NumClicks value; AdInput inputArg = default; Output output = default; AdSimpleFunctions functions1 = new(1); AdSimpleFunctions functions2 = new(2); var session1 = fht1.NewSession(functions1); for (int key = 0; key < numOps; key++) { value.numClicks = key; if ((key & 1) > 0) { session1.Upsert(ref inputArray[key], ref value, Empty.Default, 0); } else { AdInput input = new() { adId = inputArray[key], numClicks = value }; session1.RMW(ref inputArray[key], ref input); } } fht1.TryInitiateFullCheckpoint(out Guid token, CheckpointType.FoldOver); fht1.CompleteCheckpointAsync().AsTask().GetAwaiter().GetResult(); session1.Dispose(); fht2.Recover(token); var session2 = fht2.NewSession(functions2); // Just need one operation here to verify readInfo/upsertInfo in the functions var lastKey = inputArray.Length - 1; var status = session2.Read(ref inputArray[lastKey], ref inputArg, ref output, Empty.Default, 0); Assert.IsFalse(status.IsPending, status.ToString()); value.numClicks = lastKey; status = session2.Upsert(ref inputArray[lastKey], ref value, Empty.Default, 0); Assert.IsFalse(status.IsPending, status.ToString()); inputArg = new() { adId = inputArray[lastKey], numClicks = new NumClicks { numClicks = 0 } }; // CopyUpdater adds, so make this 0 status = session2.RMW(ref inputArray[lastKey], ref inputArg); Assert.IsFalse(status.IsPending, status.ToString()); // Now verify Pending fht2.Log.FlushAndEvict(wait: true); output.value = new() { numClicks = lastKey }; inputArg.numClicks = new() { numClicks = lastKey }; status = session2.Read(ref inputArray[lastKey], ref inputArg, ref output, Empty.Default, 0); Assert.IsTrue(status.IsPending, status.ToString()); session2.CompletePending(wait: true); // Upsert does not go pending so is skipped here --lastKey; output.value = new() { numClicks = lastKey }; inputArg.numClicks = new() { numClicks = lastKey }; status = session2.RMW(ref inputArray[lastKey], ref inputArg); Assert.IsTrue(status.IsPending, status.ToString()); session2.CompletePending(wait: true); session2.Dispose(); } } public class AdSimpleFunctions : FunctionsBase <AdId, NumClicks, AdInput, Output, Empty> { long expectedVersion;