/// <summary> /// Copy to given SpanByteAndMemory (header length and payload copied to actual span/memory) /// </summary> /// <param name="src"></param> /// <param name="dst"></param> /// <param name="memoryPool"></param> private unsafe void CopyWithHeaderTo(ref SpanByte src, ref SpanByteAndMemory dst, MemoryPool <byte> memoryPool) { if (dst.IsSpanByte) { if (dst.Length >= src.TotalSize) { dst.Length = src.TotalSize; var span = dst.SpanByte.AsSpan(); fixed(byte *ptr = span) * (int *)ptr = src.Length; src.AsReadOnlySpan().CopyTo(span.Slice(sizeof(int))); return; } dst.ConvertToHeap(); } dst.Length = src.TotalSize; dst.Memory = memoryPool.Rent(src.TotalSize); dst.Length = src.TotalSize; fixed(byte *ptr = dst.Memory.Memory.Span) * (int *)ptr = src.Length; src.AsReadOnlySpan().CopyTo(dst.Memory.Memory.Span.Slice(sizeof(int))); }
public unsafe void SpanByteTest1() { Span <byte> output = stackalloc byte[20]; SpanByte input = default; using var log = Devices.CreateLogDevice(TestContext.CurrentContext.TestDirectory + "/hlog1.log", deleteOnClose: true); using var fht = new FasterKV <SpanByte, SpanByte> (128, new LogSettings { LogDevice = log, MemorySizeBits = 17, PageSizeBits = 12 }); using var s = fht.NewSession(new SpanByteFunctions <Empty>()); var key1 = MemoryMarshal.Cast <char, byte>("key1".AsSpan()); var value1 = MemoryMarshal.Cast <char, byte>("value1".AsSpan()); var output1 = SpanByteAndMemory.FromFixedSpan(output); s.Upsert(key1, value1); s.Read(key1, ref input, ref output1); Assert.IsTrue(output1.IsSpanByte); Assert.IsTrue(output1.SpanByte.AsReadOnlySpan().SequenceEqual(value1)); var key2 = MemoryMarshal.Cast <char, byte>("key2".AsSpan()); var value2 = MemoryMarshal.Cast <char, byte>("value2value2value2".AsSpan()); var output2 = SpanByteAndMemory.FromFixedSpan(output); s.Upsert(key2, value2); s.Read(key2, ref input, ref output2); Assert.IsTrue(!output2.IsSpanByte); Assert.IsTrue(output2.Memory.Memory.Span.Slice(0, output2.Length).SequenceEqual(value2)); }
/// <inheritdoc /> public unsafe override void ConcurrentReader(ref SpanByte key, ref SpanByte input, ref SpanByte value, ref SpanByteAndMemory dst) { if (wireFormat != WireFormat.ASCII) { CopyWithHeaderTo(ref value, ref dst, memoryPool); } }
/// <inheritdoc /> public override void ConcurrentReader(ref SpanByte key, ref SpanByte input, ref SpanByte value, ref SpanByteAndMemory dst, ref RecordInfo recordInfo, long address) => CopyWithHeaderTo(ref value, ref dst, memoryPool);
/// <inheritdoc /> public override void SingleReader(ref SpanByte key, ref SpanByte input, ref SpanByte value, ref SpanByteAndMemory dst, long address) => CopyWithHeaderTo(ref value, ref dst, memoryPool);
/// <inheritdoc/> public override void CopyUpdater(ref SpanByte key, ref SpanByte input, ref SpanByte oldValue, ref SpanByte newValue, ref SpanByteAndMemory output) { long curr = Utils.BytesToLong(oldValue.AsSpan()); long next = curr + Utils.BytesToLong(input.AsSpan()); Debug.Assert(Utils.NumDigits(next) == newValue.Length, "Unexpected destination length in CopyUpdater"); Utils.LongToBytes(next, newValue.AsSpan()); }
public static void Run() { const bool useRmw = true; const int baseNumber = 45; // VarLen types do not need an object log using var log = Devices.CreateLogDevice("hlog.log", deleteOnClose: true); // Create store // For custom varlen (not SpanByte), you need to provide IVariableLengthStructSettings and IFasterEqualityComparer. // For this test we require record-level locking using var store = new FasterKV <SpanByte, SpanByte>( size: 1L << 20, logSettings: new LogSettings { LogDevice = log, MemorySizeBits = 15, PageSizeBits = 12 }, disableLocking: false); // Create session for ASCII sums. We require two callback function types to be provided: // AsciiSumSpanByteFunctions implements RMW callback functions // AsciiSumVLS implements the callback for computing the length of the result new value, given an old value and an input using var s = store.For(new AsciiSumSpanByteFunctions()).NewSession <AsciiSumSpanByteFunctions> (sessionVariableLengthStructSettings: new SessionVariableLengthStructSettings <SpanByte, SpanByte> { valueLength = new AsciiSumVLS() }); // Create key Span <byte> key = stackalloc byte[10]; key.Fill(23); var _key = SpanByte.FromFixedSpan(key); // Create input Span <byte> input = stackalloc byte[10]; int inputLength = Utils.LongToBytes(baseNumber, input); var _input = SpanByte.FromFixedSpan(input.Slice(0, inputLength)); if (useRmw) { s.RMW(_key, _input); // InitialUpdater to 45 (baseNumber) s.RMW(_key, _input); // InPlaceUpdater to 90 s.RMW(_key, _input); // CopyUpdater to 135 (due to value size increase) s.RMW(_key, _input); // InPlaceUpdater to 180 store.Log.Flush(true); // Flush by moving ReadOnly address to Tail (retain records in memory) s.RMW(_key, _input); // CopyUpdater to 225 (due to immutable source value in read-only region) store.Log.FlushAndEvict(true); // Flush and evict all records to disk var _status = s.RMW(_key, _input); // CopyUpdater to 270 (due to immutable source value on disk) if (_status.IsPending) { Console.WriteLine("Error!"); return; } s.CompletePending(true); // Wait for IO completion } else { s.Upsert(_key, _input); } // Create output space Span <byte> output = stackalloc byte[10]; var outputWrapper = new SpanByteAndMemory(SpanByte.FromFixedSpan(output)); var status = s.Read(ref _key, ref outputWrapper); // Read does not go pending, and the output should fit in the provided space (10 bytes) // Hence, no Memory will be allocated by FASTER if (!status.Found || !outputWrapper.IsSpanByte) { Console.WriteLine("Error!"); return; } // Check result value correctness if (useRmw) { inputLength = Utils.LongToBytes(baseNumber * 6, input); } if (!outputWrapper.SpanByte.AsReadOnlySpan().SequenceEqual(input.Slice(0, inputLength))) { Console.WriteLine("Error!"); return; } Console.WriteLine("AsciiSumSample: Success!"); }
/// <inheritdoc/> public override void InitialUpdater(ref SpanByte key, ref SpanByte input, ref SpanByte value, ref SpanByteAndMemory output) { input.CopyTo(ref value); }
/// <inheritdoc/> public override bool InPlaceUpdater(ref SpanByte key, ref SpanByte input, ref SpanByte value, ref SpanByteAndMemory output) { long curr = Utils.BytesToLong(value.AsSpan()); long next = curr + Utils.BytesToLong(input.AsSpan()); if (Utils.NumDigits(next) > value.Length) { return(false); } Utils.LongToBytes(next, value.AsSpan()); return(true); }
/// <inheritdoc /> public unsafe override void SingleReader(ref SpanByte key, ref SpanByte input, ref SpanByte value, ref SpanByteAndMemory dst) { if (wireFormat == WireFormat.Binary) { CopyWithHeaderTo(ref value, ref dst, memoryPool); } }
/// <inheritdoc /> public override void ConcurrentReader(ref SpanByte key, ref SpanByte input, ref SpanByte value, ref SpanByteAndMemory dst) => CopyWithHeaderTo(ref value, ref dst, memoryPool);
/// <inheritdoc /> public override void SingleReader(ref SpanByte key, ref SpanByte input, ref SpanByte value, ref SpanByteAndMemory dst) => ConcurrentReader(ref key, ref input, ref value, ref dst);
/// <inheritdoc/> public override bool InitialUpdater(ref SpanByte key, ref SpanByte input, ref SpanByte value, ref SpanByteAndMemory output, ref RMWInfo rmwInfo) { input.CopyTo(ref value); return(true); }
/// <inheritdoc /> public override bool SingleReader(ref SpanByte key, ref SpanByte input, ref SpanByte value, ref SpanByteAndMemory dst, ref ReadInfo readInfo) => CopyWithHeaderTo(ref value, ref dst, memoryPool);