### Install Jering.KeyValueStore Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Commands for adding the library to a .NET project via CLI or Package Manager. ```bash # Using Package Manager PM> Install-Package Jering.KeyValueStore # Using .NET CLI dotnet add package Jering.KeyValueStore ``` -------------------------------- ### Install Jering.KeyValueStore via Package Manager Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Use this command in the Package Manager Console to install the Jering.KeyValueStore NuGet package. ```powershell PM> Install-Package Jering.KeyValueStore ``` -------------------------------- ### Install Jering.KeyValueStore via .NET CLI Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Use this command in the .NET CLI to add the Jering.KeyValueStore package to your project. ```bash > dotnet add package Jering.KeyValueStore ``` -------------------------------- ### Memory and disk storage layout Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Examples showing how records are distributed across memory, disk, and segments. ```text // In-memory region key: 0, value: "dummyString2" key: 1, value: "dummyString2" key: 2, value: "dummyString2" // On-disk region key: 3, value: "dummyString2" key: 4, value: "dummyString2" key: 5, value: "dummyString2" ``` ```text // On-disk region // Segment 0, full key: 3, value: "dummyString2" key: 4, value: "dummyString2" key: 5, value: "dummyString2" // Segment 1, partially filled key: 6, value: "dummyString2" empty empty ``` -------------------------------- ### Log structure examples Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Visual representations of the log state during insertions, updates, and compaction. ```text // Head key: 0, value: "dummyString1" key: 1, value: "dummyString1" key: 2, value: "dummyString1" // Tail - records are added here ``` ```text // Head key: 0, value: "dummyString1" key: 1, value: "dummyString1" key: 2, value: "dummyString1" // Index points to these - the most recent records for each key key: 0, value: "dummyString2" key: 1, value: "dummyString2" key: 2, value: "dummyString2" // Tail ``` ```text key: 0, value: "dummyString2" key: 1, value: "dummyString2" key: 2, value: "dummyString2" ``` -------------------------------- ### Concurrent Operations with MixedStorageKVStore Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Demonstrates thread-safe concurrent inserts, reads, updates, and deletes using MixedStorageKVStore. Suitable for highly concurrent scenarios. Ensure proper setup and verification of operations. ```csharp var mixedStorageKVStore = new MixedStorageKVStore(); int numRecords = 100_000; // Concurrent inserts ConcurrentQueue upsertTasks = new(); Parallel.For(0, numRecords, key => upsertTasks.Enqueue(mixedStorageKVStore.UpsertAsync(key, "dummyString1"))); await Task.WhenAll(upsertTasks).ConfigureAwait(false); // Concurrent reads ConcurrentQueue> readTasks = new(); Parallel.For(0, numRecords, key => readTasks.Enqueue(mixedStorageKVStore.ReadAsync(key))); foreach (ValueTask<(Status, string?)> task in readTasks) { // Verify Assert.Equal((Status.OK, "dummyString1"), await task.ConfigureAwait(false)); } // Concurrent updates upsertTasks.Clear(); Parallel.For(0, numRecords, key => upsertTasks.Enqueue(mixedStorageKVStore.UpsertAsync(key, "dummyString2"))); await Task.WhenAll(upsertTasks).ConfigureAwait(false); // Read again so we can verify updates readTasks.Clear(); Parallel.For(0, numRecords, key => readTasks.Enqueue(mixedStorageKVStore.ReadAsync(key))); foreach (ValueTask<(Status, string?)> task in readTasks) { // Verify Assert.Equal((Status.OK, "dummyString2"), await task.ConfigureAwait(false)); } // Concurrent deletes ConcurrentQueue> deleteTasks = new(); Parallel.For(0, numRecords, key => deleteTasks.Enqueue(mixedStorageKVStore.DeleteAsync(key))); foreach (ValueTask task in deleteTasks) { Status result = await task.ConfigureAwait(false); // Verify Assert.Equal(Status.OK, result); } // Read again so we can verify deletes readTasks.Clear(); Parallel.For(0, numRecords, key => readTasks.Enqueue(mixedStorageKVStore.ReadAsync(key))); foreach (ValueTask<(Status, string?)> task in readTasks) { // Verify Assert.Equal((Status.NOTFOUND, null), await task.ConfigureAwait(false)); } ``` -------------------------------- ### LogFileNamePrefix Property for MixedStorageKVStoreOptions Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Determines the prefix for Faster log segment filenames. If null or empty, a random GUID is used. This setting is ignored if a FasterKV instance is provided. ```csharp public string? LogFileNamePrefix { get; set; } ``` -------------------------------- ### Initialize MixedStorageKVStore Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Instantiate the store with default settings, custom configuration options, or integrated logging. ```csharp using Jering.KeyValueStore; using Microsoft.Extensions.Logging; // Basic instantiation with defaults var store = new MixedStorageKVStore(); // With custom options var options = new MixedStorageKVStoreOptions() { LogDirectory = "/var/data/kvstore", MemorySizeBits = 26, // 67 MB in-memory region PageSizeBits = 25, // 33.5 MB page size DeleteLogOnClose = true, TimeBetweenLogCompactionsMS = 60000 }; var configuredStore = new MixedStorageKVStore(options); // With logging support ILogger> logger = loggerFactory.CreateLogger>(); var loggedStore = new MixedStorageKVStore(options, logger); ``` -------------------------------- ### Configure MixedStorageKVStore with Options Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Configure a MixedStorageKVStore by passing a MixedStorageKVStoreOptions instance during initialization. Specify options like LogDirectory as needed. ```csharp var mixedStorageKVStoreOptions = new MixedStorageKVStoreOptions() { // Specify options LogDirectory = "my/log/directory", ... }; var mixedStorageKVStore = new MixedStorageKVStore(mixedStorageKVStoreOptions); ``` -------------------------------- ### Advanced Configuration with FasterKV Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md For greater control, initialize MixedStorageKVStore with a manually configured FasterKV instance. This allows for advanced performance tuning. ```csharp var logSettings = new LogSettings() // Faster options type { // Specify options ... }; var fasterKV = new FasterKV(1L << 20, logSettings)); // Manually configured FasterKV var mixedStorageKVStoreOptions = new MixedStorageKVStoreOptions() { // Specify options LogDirectory = "my/log/directory", ... }; var mixedStorageKVStore = new MixedStorageKVStore(mixedStorageKVStoreOptions, fasterKVStore: fasterKV); ``` -------------------------------- ### MixedStorageKVStore Constructor Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Demonstrates how to create a new key-value store instance with default or custom options, including logging support. ```APIDOC ## MixedStorageKVStore Constructor ### Description Creates a new key-value store instance with optional configuration and logging. The store automatically manages sessions, serialization, and periodic log compaction in the background. ### Method Constructor ### Endpoint N/A (Class Constructor) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp using Jering.KeyValueStore; using Microsoft.Extensions.Logging; // Basic instantiation with defaults var store = new MixedStorageKVStore(); // With custom options var options = new MixedStorageKVStoreOptions() { LogDirectory = "/var/data/kvstore", MemorySizeBits = 26, // 67 MB in-memory region PageSizeBits = 25, // 33.5 MB page size DeleteLogOnClose = true, TimeBetweenLogCompactionsMS = 60000 }; var configuredStore = new MixedStorageKVStore(options); // With logging support ILogger> logger = loggerFactory.CreateLogger>(); var loggedStore = new MixedStorageKVStore(options, logger); ``` ### Response N/A (Constructor) ``` -------------------------------- ### Advanced Configuration with Custom FasterKV in C# Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Shows how to provide a manually configured FasterKV instance to MixedStorageKVStore for advanced control over Faster's behavior, including custom log settings. ```csharp using Jering.KeyValueStore; using FASTER.core; // Create custom log settings var logSettings = new LogSettings() { LogDevice = Devices.CreateLogDevice( "/var/data/custom.log", preallocateFile: true, deleteOnClose: true ), PageSizeBits = 12, MemorySizeBits = 13, SegmentSizeBits = 28 }; // Create custom FasterKV instance var fasterKV = new FasterKV(1L << 20, logSettings); // Use custom FasterKV with MixedStorageKVStore var options = new MixedStorageKVStoreOptions() { TimeBetweenLogCompactionsMS = 30_000 }; var store = new MixedStorageKVStore(options, fasterKVStore: fasterKV); // Access underlying FasterKV if needed FasterKV underlyingStore = store.FasterKV; ``` -------------------------------- ### Initialize MixedStorageKVStore with On-Disk Storage Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Use this to initialize a MixedStorageKVStore that writes data to disk. Configure memory size, page size, and whether to delete log files on close. ```csharp var mixedStorageKVStoreOptions = new MixedStorageKVStoreOptions() { PageSizeBits = 12, // See MixedStorageKVStoreOptions.PageSizeBits in the MixedStorageKVStoreOptions section above MemorySizeBits = 13, DeleteLogOnClose = false // Disables automatic deleting of files on disk. See MixedStorageKVStoreOptions.DeleteLogOnClose in the MixedStorageKVStoreOptions section above }; var mixedStorageKVStore = new MixedStorageKVStore(mixedStorageKVStoreOptions); // Insert ConcurrentQueue upsertTasks = new(); Parallel.For(0, 100_000, key => upsertTasks.Enqueue(mixedStorageKVStore.UpsertAsync(key, "dummyString1"))); await Task.WhenAll(upsertTasks).ConfigureAwait(false); ``` -------------------------------- ### Configure MixedStorageKVStore Options Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Shows how to configure the MixedStorageKVStore with custom options for index, memory, storage, file paths, compaction, and serialization. ```csharp using Jering.KeyValueStore; using MessagePack; var options = new MixedStorageKVStoreOptions() { // Index configuration (64-bit buckets) IndexNumBuckets = 1L << 20, // 1,048,576 buckets (64 MB index) // Memory and storage sizing (powers of 2) PageSizeBits = 25, // 2^25 = 33.5 MB per page MemorySizeBits = 26, // 2^26 = 67 MB in-memory region SegmentSizeBits = 28, // 2^28 = 268 MB per disk segment // File storage location LogDirectory = "/var/data/myapp/cache", // Custom directory (default: temp path) LogFileNamePrefix = "myapp-cache", // Custom prefix (default: random GUID) DeleteLogOnClose = true, // Auto-delete files on dispose // Log compaction settings TimeBetweenLogCompactionsMS = 60_000, // 60 seconds between compaction attempts InitialLogCompactionThresholdBytes = 0, // 0 = 2 * memory size // Serialization (MessagePack with LZ4 compression) MessagePackSerializerOptions = MessagePackSerializerOptions.Standard .WithCompression(MessagePackCompression.Lz4BlockArray) }; var store = new MixedStorageKVStore(options); ``` -------------------------------- ### MixedStorageKVStoreOptions Configuration Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Configuration options for initializing the MixedStorageKVStore. ```APIDOC ## MixedStorageKVStoreOptions Class ### Properties - **IndexNumBuckets** (long) - The number of buckets in Faster's index. Defaults to 1048576. - **PageSizeBits** (int) - The size of a page in Faster's log. Defaults to 25. - **MemorySizeBits** (int) - The size of the in-memory region of Faster's log. Defaults to 26. - **SegmentSizeBits** (int) - The size of a segment of the on-disk region of Faster's log. Defaults to 28. - **LogDirectory** (string?) - The directory containing the on-disk region of Faster's log. Defaults to null. - **LogFileNamePrefix** (string?) - The Faster log filename prefix. Defaults to null. - **TimeBetweenLogCompactionsMS** (int) - The time between Faster log compaction attempts. Defaults to 60000. - **InitialLogCompactionThresholdBytes** (long) - The initial log compaction threshold. Defaults to 0. ``` -------------------------------- ### MixedStorageKVStore Constructor with Options Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md This constructor creates a MixedStorageKVStore instance with specified options, logger, and an optional pre-configured FasterKV store. ```csharp public MixedStorageKVStore([MixedStorageKVStoreOptions? mixedStorageKVStoreOptions = null], [ILogger>? logger = null], [FasterKV? fasterKVStore = null]) ``` -------------------------------- ### Session management in FasterKV and MixedStorageKeyValueStore Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Comparison between manual session management in FasterKV and the thread-safe abstraction provided by MixedStorageKeyValueStore. ```csharp // Create FasterKV instance FasterKV fasterKV = new(1L << 20, logSettings); // logSettings is an instance of LogSettings // Create session var session = fasterKV.For(simpleFunctions).NewSession>(); // simpleFunction is an instance of SimpleFunctions // Perform operations await session.UpsertAsync(0, "dummyString").ConfigureAwait(false); // Not thread-safe. You need to manage a pool of sessions for multi-threaded logic. ``` ```csharp // Create MixedStorageKeyValueStore instance MixedStorageKeyValueStore mixedStorageKeyValueStore = new(); // Perform operations await mixedStorageKeyValueStore.UpsertAsync().ConfigureAwait(false); // Thread-safe ``` -------------------------------- ### MixedStorageKVStore Constructor Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Initializes a new instance of the MixedStorageKVStore class with optional configuration, logger, and underlying FasterKV store. ```APIDOC ## Constructor MixedStorageKVStore ### Description Creates a MixedStorageKVStore instance. ### Parameters - **mixedStorageKVStoreOptions** (MixedStorageKVStoreOptions) - Optional - The options for the store. - **logger** (ILogger) - Optional - The logger for log compaction events. - **fasterKVStore** (FasterKV) - Optional - The underlying FasterKV instance. ``` -------------------------------- ### Default Constructor for MixedStorageKVStoreOptions Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Initializes a new instance of the MixedStorageKVStoreOptions class with default settings. Use this to configure the underlying Faster KV store. ```csharp public MixedStorageKVStoreOptions() ``` -------------------------------- ### Basic Key-Value Store Operations Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Demonstrates inserting, reading, updating, and deleting key-value pairs using MixedStorageKVStore. Ensure keys and values are serializable by MessagePack C#. ```csharp var mixedStorageKVStore = new MixedStorageKVStore(); // Stores data across memory (primary storage) and disk (secondary storage) // Insert await mixedStorageKVStore.UpsertAsync(0, "dummyString1").ConfigureAwait(false); // Insert a key-value pair (record) // Verify inserted (Status status, string? result) = await mixedStorageKVStore.ReadAsync(0).ConfigureAwait(false); Assert.Equal(Status.OK, status); // Status.NOTFOUND if no record with key 0 Assert.Equal("dummyString1", result); // Update await mixedStorageKVStore.UpsertAsync(0, "dummyString2").ConfigureAwait(false); // Verify updated (status, result) = await mixedStorageKVStore.ReadAsync(0).ConfigureAwait(false); Assert.Equal(Status.OK, status); Assert.Equal("dummyString2", result); // Delete await mixedStorageKVStore.DeleteAsync(0).ConfigureAwait(false); // Verify deleted (status, result) = await mixedStorageKVStore.ReadAsync(0).ConfigureAwait(false); Assert.Equal(Status.NOTFOUND, status); Assert.Null(result); ``` -------------------------------- ### Upserting with MixedStorageKVStore Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Demonstrates using MixedStorageKVStore to automatically handle serialization of variable-length types using MessagePack. ```csharp var mixedStorageKVStore = new MixedStorageKVStore(); // Upsert updates or inserts records. // // Under-the-hood, MixedStorageKeyValueStore serializes dummyClassInstance using the MessagePack C# library, // creates a `SpanByte` around the resultant data, and passes the `SpanByte` to the underlying FasterKV instance. mixedStorageKVStore.Upsert(0, dummyClassInstance); ``` -------------------------------- ### LogDirectory Property for MixedStorageKVStoreOptions Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Sets the directory for Faster's on-disk log files. If null or empty, logs are placed in a temporary directory. This setting is ignored if a FasterKV instance is provided. ```csharp public string? LogDirectory { get; set; } ``` -------------------------------- ### Benchmark Environment Configuration Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Environment details for the BenchmarkDotNet performance tests. ```ini BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.928 (2004/?/20H1) Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores .NET Core SDK=5.0.300-preview.21180.15 [Host] : .NET Core 5.0.6 (CoreCLR 5.0.621.22011, CoreFX 5.0.621.22011), X64 RyuJIT Job-JXJRVC : .NET Core 5.0.6 (CoreCLR 5.0.621.22011, CoreFX 5.0.621.22011), X64 RyuJIT InvocationCount=1 UnrollFactor=1 ``` -------------------------------- ### Use Custom Key and Value Types Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Demonstrates using custom serializable classes and structs as key-value types with MessagePack annotations. ```csharp using Jering.KeyValueStore; using MessagePack; // Custom class with MessagePack annotations [MessagePackObject] public class Product { [Key(0)] public string? Sku { get; set; } [Key(1)] public string? Name { get; set; } [Key(2)] public decimal Price { get; set; } [Key(3)] public string[]? Tags { get; set; } } // Custom struct (value type) [MessagePackObject] public struct CacheEntry { [Key(0)] public byte[] Data { get; set; } [Key(1)] public long Timestamp { get; set; } [Key(2)] public int ExpiresInSeconds { get; set; } } // Using custom class as value var productStore = new MixedStorageKVStore(); await productStore.UpsertAsync("SKU-12345", new Product { Sku = "SKU-12345", Name = "Widget Pro", Price = 29.99m, Tags = new[] { "electronics", "gadgets", "popular" } }).ConfigureAwait(false); // Using custom struct var cacheStore = new MixedStorageKVStore(); await cacheStore.UpsertAsync("session:abc123", new CacheEntry { Data = System.Text.Encoding.UTF8.GetBytes("session data"), Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), ExpiresInSeconds = 3600 }).ConfigureAwait(false); // Using primitives var intStore = new MixedStorageKVStore(); await intStore.UpsertAsync(1, 12345).ConfigureAwait(false); ``` -------------------------------- ### MixedStorageKVStoreOptions Configuration Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Configuration class for customizing store behavior including memory limits, disk storage location, log compaction settings, and serialization options. ```APIDOC ## MixedStorageKVStoreOptions ### Description Configuration class for customizing store behavior including memory limits, disk storage location, log compaction settings, and serialization options. ### Parameters #### Request Body - **IndexNumBuckets** (long) - Optional - Number of buckets for the index. - **PageSizeBits** (int) - Optional - Size of memory pages. - **MemorySizeBits** (int) - Optional - Size of the in-memory region. - **SegmentSizeBits** (int) - Optional - Size of disk segments. - **LogDirectory** (string) - Optional - File system path for storage. - **LogFileNamePrefix** (string) - Optional - Prefix for log files. - **DeleteLogOnClose** (bool) - Optional - Whether to delete files on dispose. - **TimeBetweenLogCompactionsMS** (int) - Optional - Interval for log compaction. - **InitialLogCompactionThresholdBytes** (long) - Optional - Threshold for triggering compaction. - **MessagePackSerializerOptions** (MessagePackSerializerOptions) - Optional - Serialization settings. ``` -------------------------------- ### InitialLogCompactionThresholdBytes Property for MixedStorageKVStoreOptions Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Sets the initial threshold in bytes for triggering log compactions. If the safe-readonly region exceeds this, compaction runs. This value is internal. ```csharp public long InitialLogCompactionThresholdBytes { get; internal set; } ``` -------------------------------- ### TimeBetweenLogCompactionsMS Property for MixedStorageKVStoreOptions Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Configures the interval in milliseconds between Faster log compaction attempts. A negative value disables compaction. Defaults to 60000ms. ```csharp public int TimeBetweenLogCompactionsMS { get; set; } ``` -------------------------------- ### Delete FasterLogs Directory on Application Initialization Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md This C# code snippet demonstrates how to safely delete the FasterLogs directory on application startup to ensure a clean state for MixedStorageKVStore. It includes error handling for cases where the directory might not exist. ```csharp try { Directory.Delete(Path.Combine(Path.GetTempPath(), "FasterLogs"), true); } catch { // Do nothing } ``` -------------------------------- ### PageSizeBits Property for MixedStorageKVStoreOptions Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Configures the size of a page in Faster's log. A page is a contiguous block of storage. This setting is ignored if a FasterKV instance is provided. ```csharp public int PageSizeBits { get; set; } ``` -------------------------------- ### IndexNumBuckets Property for MixedStorageKVStoreOptions Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Sets the number of buckets in Faster's index. Each bucket is 64 bits. This setting is ignored if a FasterKV instance is provided. ```csharp public long IndexNumBuckets { get; set; } ``` -------------------------------- ### MixedStorageKVStoreOptions Configuration Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Configuration properties for the MixedStorageKVStore, including log deletion behavior and MessagePack serialization options. ```APIDOC ## MixedStorageKVStoreOptions ### Description Configuration options for the MixedStorageKVStore component. ### Properties - **DeleteLogOnClose** (bool) - Specifies whether log files are deleted when the store is disposed or finalized. Defaults to true. Note: This value is ignored if a FasterKV instance is provided. - **MessagePackSerializerOptions** (MessagePackSerializerOptions) - Options for serializing data using MessagePack C#. Defaults to Standard with Lz4BlockArray compression. ``` -------------------------------- ### Configure MessagePackSerializerOptions Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Sets the serialization options for MessagePack C#. Defaults to standard options with Lz4BlockArray compression. ```csharp public MessagePackSerializerOptions MessagePackSerializerOptions { get; set; } ``` -------------------------------- ### MemorySizeBits Property for MixedStorageKVStoreOptions Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Defines the size of the in-memory region of Faster's log. If the log exceeds this size, overflow is moved to disk. This setting is ignored if a FasterKV instance is provided. ```csharp public int MemorySizeBits { get; set; } ``` -------------------------------- ### Configure DeleteLogOnClose Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Specifies whether log files are deleted upon disposal or finalization. This setting is ignored if a FasterKV instance is provided to the constructor. ```csharp public bool DeleteLogOnClose { get; set; } ``` -------------------------------- ### Use custom reference type in MixedStorageKVStore Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Demonstrates upserting and reading a custom reference type instance. ```csharp var mixedStorageKVStore = new MixedStorageKVStore(); // string key, DummyClass value var dummyClassInstance = new DummyClass() { DummyString = "dummyString", DummyStringArray = new[] { "dummyString1", "dummyString2", "dummyString3", "dummyString4", "dummyString5" }, DummyInt = 10, DummyIntArray = new[] { 10, 100, 1000, 10000, 100000, 1000000, 10000000 } }; // Insert await mixedStorageKVStore.UpsertAsync("dummyKey", dummyClassInstance).ConfigureAwait(false); // Read (Status status, DummyClass? result) = await mixedStorageKVStore.ReadAsync("dummyKey").ConfigureAwait(false); // Verify Assert.Equal(Status.OK, status); Assert.Equal(dummyClassInstance.DummyString, result!.DummyString); // result is only null if status is Status.NOTFOUND Assert.Equal(dummyClassInstance.DummyStringArray, result!.DummyStringArray); Assert.Equal(dummyClassInstance.DummyInt, result!.DummyInt); Assert.Equal(dummyClassInstance.DummyIntArray, result!.DummyIntArray); ``` -------------------------------- ### Delete Record Asynchronously Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Demonstrates deleting a record by key and verifying its deletion. Also shows thread-safe concurrent deletes. ```csharp using Jering.KeyValueStore; using FASTER.core; var store = new MixedStorageKVStore(); // Insert a record await store.UpsertAsync(42, "temporary data").ConfigureAwait(false); // Delete the record Status deleteStatus = await store.DeleteAsync(42).ConfigureAwait(false); if (deleteStatus == Status.OK) { Console.WriteLine("Record deleted successfully"); } // Verify deletion (Status readStatus, string? value) = await store.ReadAsync(42).ConfigureAwait(false); // readStatus == Status.NOTFOUND, value == null // Concurrent deletes (thread-safe) var deleteTasks = new ConcurrentQueue>(); Parallel.For(0, 10000, key => deleteTasks.Enqueue(store.DeleteAsync(key))); foreach (var task in deleteTasks) { Status status = await task.ConfigureAwait(false); // status == Status.OK for successful deletes } ``` -------------------------------- ### Dispose MixedStorageKVStore in C# Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Demonstrates automatic disposal using a 'using' statement and manual disposal with a 'try-finally' block. Operations on a disposed store will throw an ObjectDisposedException. ```csharp using Jering.KeyValueStore; // Using statement for automatic disposal using (var store = new MixedStorageKVStore()) { await store.UpsertAsync(1, "data").ConfigureAwait(false); (var status, var value) = await store.ReadAsync(1).ConfigureAwait(false); // Store is automatically disposed at end of block } // Manual disposal var manualStore = new MixedStorageKVStore(); try { await manualStore.UpsertAsync(1, "data").ConfigureAwait(false); } finally { manualStore.Dispose(); } // After disposal, operations throw ObjectDisposedException var disposedStore = new MixedStorageKVStore(); disposedStore.Dispose(); try { await disposedStore.UpsertAsync(1, "data").ConfigureAwait(false); } catch (ObjectDisposedException ex) { Console.WriteLine("Store has been disposed"); } ``` -------------------------------- ### Demonstrate mutable key type pitfalls Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Shows how modifying a mutable object after insertion prevents retrieval because the binary serialized form is used as the key. ```csharp var mixedStorageKVStore = new MixedStorageKVStore(); var dummyClassInstance = new DummyClass() { DummyString = "dummyString", DummyStringArray = new[] { "dummyString1", "dummyString2", "dummyString3", "dummyString4", "dummyString5" }, DummyInt = 10, DummyIntArray = new[] { 10, 100, 1000, 10000, 100000, 1000000, 10000000 } }; // Insert await mixedStorageKVStore.UpsertAsync(dummyClassInstance, "dummyKey").ConfigureAwait(false); // Read dummyClassInstance.DummyInt = 11; // Change a member (Status status, string? result) = await mixedStorageKVStore.ReadAsync(dummyClassInstance).ConfigureAwait(false); // Verify Assert.Equal(Status.NOTFOUND, status); // No value for given key Assert.Null(result); ``` -------------------------------- ### MixedStorageKVStore FasterKV Property Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md This property provides access to the underlying FasterKV instance used by MixedStorageKVStore. ```csharp public FasterKV FasterKV { get; } ``` -------------------------------- ### Use custom value type in MixedStorageKVStore Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Demonstrates upserting and reading a custom value type instance. ```csharp var mixedStorageKVStore = new MixedStorageKVStore(); // int key, DummyStruct value var dummyStructInstance = new DummyStruct() { // Populate with dummy values DummyByte = byte.MaxValue, DummyShort = short.MaxValue, DummyInt = int.MaxValue, DummyLong = long.MaxValue }; // Insert await mixedStorageKVStore.UpsertAsync(0, dummyStructInstance).ConfigureAwait(false); // Read (Status status, DummyStruct result) = await mixedStorageKVStore.ReadAsync(0).ConfigureAwait(false); // Verify Assert.Equal(Status.OK, status); Assert.Equal(dummyStructInstance.DummyByte, result.DummyByte); Assert.Equal(dummyStructInstance.DummyShort, result.DummyShort); Assert.Equal(dummyStructInstance.DummyInt, result.DummyInt); Assert.Equal(dummyStructInstance.DummyLong, result.DummyLong); ``` -------------------------------- ### Dispose Method for MixedStorageKVStore Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Disposes the current instance of MixedStorageKVStore. Call this method when you are finished with the store to release resources. ```csharp public void Dispose() ``` -------------------------------- ### Define a custom reference type with MessagePack Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Annotate a class with [MessagePackObject] and [Key] attributes to enable serialization. ```csharp [MessagePackObject] // MessagePack C# attribute public class DummyClass { [Key(0)] // MessagePack C# attribute public string? DummyString { get; set; } [Key(1)] public string[]? DummyStringArray { get; set; } [Key(2)] public int DummyInt { get; set; } [Key(3)] public int[]? DummyIntArray { get; set; } } ``` -------------------------------- ### SegmentSizeBits Property for MixedStorageKVStoreOptions Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Specifies the size of a segment in the on-disk region of Faster's log. Segments are pre-allocated files. This setting is ignored if a FasterKV instance is provided. ```csharp public int SegmentSizeBits { get; set; } ``` -------------------------------- ### Read Records Asynchronously Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Retrieve values by key and handle operation status, including concurrent read scenarios. ```csharp using Jering.KeyValueStore; using FASTER.core; var store = new MixedStorageKVStore(); // Insert a record await store.UpsertAsync("config:timeout", "30000").ConfigureAwait(false); // Read the record (Status status, string? value) = await store.ReadAsync("config:timeout").ConfigureAwait(false); if (status == Status.OK) { Console.WriteLine($"Value: {value}"); // Output: Value: 30000 } else if (status == Status.NOTFOUND) { Console.WriteLine("Key not found"); } // Concurrent reads (thread-safe) var readTasks = new ConcurrentQueue>(); Parallel.For(0, 10000, key => readTasks.Enqueue(store.ReadAsync($"key:{key}"))); foreach (var task in readTasks) { (Status s, string? result) = await task.ConfigureAwait(false); // Process results... } ``` -------------------------------- ### ReadAsync Method Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Reads a record asynchronously from the key-value store. ```APIDOC ## ReadAsync(TKey key) ### Description Reads a record asynchronously from the store. This method is thread-safe. ### Parameters #### Path Parameters - **key** (TKey) - Required - The record's key. ### Response #### Success Response (200) - **Result** ((Status, TValue?)) - The task representing the asynchronous operation containing the status and value. ### Exceptions - **ObjectDisposedException** - Thrown if the instance or a dependency is disposed. ``` -------------------------------- ### ReadAsync Method for MixedStorageKVStore Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Reads a record asynchronously from the key-value store. This method is thread-safe. Ensure the instance is not disposed before calling. ```csharp public ValueTask<(Status, TValue?)> ReadAsync(TKey key) ``` -------------------------------- ### Define a custom value type with MessagePack Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Annotate a struct with [MessagePackObject] and [Key] attributes. ```csharp [MessagePackObject] public struct DummyStruct { [Key(0)] public byte DummyByte { get; set; } [Key(1)] public short DummyShort { get; set; } [Key(2)] public int DummyInt { get; set; } [Key(3)] public long DummyLong { get; set; } } ``` -------------------------------- ### Custom Key and Value Types Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Supports any types serializable by MessagePack C#, including primitives, custom classes, and structs. Custom types must be annotated with MessagePack attributes. ```APIDOC ## Custom Key and Value Types ### Description Supports any types serializable by MessagePack C#, including primitives, custom classes, and structs. Custom types must be annotated with MessagePack attributes. ### Usage - **Classes/Structs**: Must be annotated with [MessagePackObject] and [Key(n)] attributes. - **Primitives**: Supported natively by the store. ``` -------------------------------- ### Upsert Records Asynchronously Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Insert or update records using thread-safe operations with custom MessagePack-serialized types. ```csharp using Jering.KeyValueStore; using MessagePack; // Define a custom value type with MessagePack attributes [MessagePackObject] public class UserProfile { [Key(0)] public string? Name { get; set; } [Key(1)] public string? Email { get; set; } [Key(2)] public int Age { get; set; } } // Create store and insert records var store = new MixedStorageKVStore(); var user = new UserProfile { Name = "John Doe", Email = "john@example.com", Age = 30 }; // Insert a new record await store.UpsertAsync(1, user).ConfigureAwait(false); // Update an existing record user.Age = 31; await store.UpsertAsync(1, user).ConfigureAwait(false); // Concurrent inserts (thread-safe) var tasks = new ConcurrentQueue(); Parallel.For(0, 100_000, key => tasks.Enqueue(store.UpsertAsync(key, user))); await Task.WhenAll(tasks).ConfigureAwait(false); ``` -------------------------------- ### ReadAsync Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Asynchronously reads a record by its key. Returns the operation status and the value (or null/default if not found). This method is thread-safe. ```APIDOC ## ReadAsync ### Description Reads a record asynchronously by its key. Returns a tuple containing the operation status and the value (or null/default if not found). This method is thread-safe. ### Method `ReadAsync(TKey key)` ### Endpoint N/A (Method within MixedStorageKVStore) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **key** (TKey) - Required - The key of the record to read. ### Request Example ```csharp using Jering.KeyValueStore; using FASTER.core; var store = new MixedStorageKVStore(); // Insert a record await store.UpsertAsync("config:timeout", "30000").ConfigureAwait(false); // Read the record (Status status, string? value) = await store.ReadAsync("config:timeout").ConfigureAwait(false); if (status == Status.OK) { Console.WriteLine($"Value: {value}"); // Output: Value: 30000 } else if (status == Status.NOTFOUND) { Console.WriteLine("Key not found"); } // Concurrent reads (thread-safe) var readTasks = new ConcurrentQueue>(); Parallel.For(0, 10000, key => readTasks.Enqueue(store.ReadAsync($"key:{key}"))); foreach (var task in readTasks) { (Status s, string? result) = await task.ConfigureAwait(false); // Process results... } ``` ### Response #### Success Response (Tuple) - **status** (Status) - Indicates the outcome of the read operation (e.g., OK, NOTFOUND). - **value** (TValue?) - The value associated with the key, or null/default if the key was not found. #### Response Example ```csharp // Example for a found key: (Status.OK, "30000") // Example for a not found key: (Status.NOTFOUND, null) ``` -------------------------------- ### UpsertAsync Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Asynchronously updates or inserts a record. If a record with the specified key exists, its value is updated; otherwise, a new record is created. This method is thread-safe. ```APIDOC ## UpsertAsync ### Description Updates or inserts a record asynchronously. If a record with the specified key exists, its value is updated; otherwise, a new record is created. This method is thread-safe and suitable for highly concurrent scenarios. ### Method `UpsertAsync(TKey key, TValue value)` ### Endpoint N/A (Method within MixedStorageKVStore) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **key** (TKey) - Required - The key of the record to upsert. - **value** (TValue) - Required - The value to associate with the key. ### Request Example ```csharp using Jering.KeyValueStore; using MessagePack; // Define a custom value type with MessagePack attributes [MessagePackObject] public class UserProfile { [Key(0)] public string? Name { get; set; } [Key(1)] public string? Email { get; set; } [Key(2)] public int Age { get; set; } } // Create store and insert records var store = new MixedStorageKVStore(); var user = new UserProfile { Name = "John Doe", Email = "john@example.com", Age = 30 }; // Insert a new record await store.UpsertAsync(1, user).ConfigureAwait(false); // Update an existing record user.Age = 31; await store.UpsertAsync(1, user).ConfigureAwait(false); // Concurrent inserts (thread-safe) var tasks = new ConcurrentQueue(); Parallel.For(0, 100_000, key => tasks.Enqueue(store.UpsertAsync(key, user))); await Task.WhenAll(tasks).ConfigureAwait(false); ``` ### Response #### Success Response (void) This method does not return a value upon successful completion. #### Response Example N/A ``` -------------------------------- ### MixedStorageKVStore UpsertAsync Method Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Asynchronously updates or inserts a record in the MixedStorageKVStore. This method is thread-safe and throws ObjectDisposedException if the instance is disposed. ```csharp public Task UpsertAsync(TKey key, TValue obj) ``` -------------------------------- ### DeleteAsync Method Source: https://context7.com/jeringtech/keyvaluestore/llms.txt Deletes a record asynchronously by its key. Returns the operation status indicating success or if the key was not found. ```APIDOC ## DeleteAsync ### Description Deletes a record asynchronously by its key. Returns the operation status indicating success or if the key was not found. This method is thread-safe. ### Method Async Task ### Parameters #### Path Parameters - **key** (TKey) - Required - The key of the record to delete. ### Response #### Success Response - **Status** (Enum) - Returns Status.OK if successful, or Status.NOTFOUND if the key does not exist. ``` -------------------------------- ### MixedStorageKVStore DeleteAsync Method Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Asynchronously deletes a record from the MixedStorageKVStore. This method is thread-safe and returns a ValueTask. It throws ObjectDisposedException if the instance is disposed. ```csharp public ValueTask DeleteAsync(TKey key) ``` -------------------------------- ### DeleteAsync Method Source: https://github.com/jeringtech/keyvaluestore/blob/main/ReadMe.md Deletes a record from the store asynchronously. ```APIDOC ## Method DeleteAsync ### Description Deletes a record asynchronously. This method is thread-safe. ### Parameters - **key** (TKey) - Required - The record's key. ### Exceptions - **ObjectDisposedException** - Thrown if the instance or a dependency is disposed. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.