|
1 | | -Lightning.NET |
2 | | -============= |
3 | | - |
| 1 | +# Lightning.NET |
4 | 2 |  |
| 3 | +[](https://www.nuget.org/packages/LightningDB/) |
| 4 | + |
| 5 | +Lightning.NET is a .NET library that provides a fast and easy-to-use interface to the Lightning Memory-Mapped Database (LMDB), a high-performance key-value store. This library enables .NET developers to leverage LMDB's efficiency and reliability in their applications. |
| 6 | + |
| 7 | +## Features |
| 8 | + |
| 9 | +- **High Performance**: Direct interaction with LMDB ensures minimal overhead (no copies / 0-alloc when using Span) and maximum speed. |
| 10 | +- **Simplicity**: The API is designed to be straightforward, making it easy to integrate into existing projects. |
| 11 | +- **Flexibility**: Supports various database configurations, including handling multiple values for the same key. |
| 12 | +- **Reliable**: It is fully transactional with complete ACID semantics. |
5 | 13 |
|
6 | | -.NET library for OpenLDAP's LMDB key-value store. |
| 14 | +## Installation |
7 | 15 |
|
8 | | -The API is easy to use and extremely fast. |
| 16 | +Lightning.NET is available as a NuGet package. To install it, run the following command in the Package Manager Console: |
9 | 17 |
|
10 | | -```cs |
| 18 | +```bash |
| 19 | +Install-Package LightningDB |
| 20 | +``` |
| 21 | + |
| 22 | +Alternatively, you can install it via the .NET CLI: |
| 23 | + |
| 24 | +```bash |
| 25 | +dotnet add package LightningDB |
| 26 | +``` |
| 27 | + |
| 28 | +## Basic Usage |
| 29 | + |
| 30 | +Here's a simple example demonstrating how to create an environment, open a database, and perform basic put and get operations: |
| 31 | + |
| 32 | +```csharp |
| 33 | +using System; |
11 | 34 | using System.Text; |
12 | 35 | using LightningDB; |
13 | 36 |
|
14 | | -using var env = new LightningEnvironment("pathtofolder"); |
15 | | -env.Open(); |
16 | | - |
17 | | -using (var tx = env.BeginTransaction()) |
18 | | -using (var db = tx.OpenDatabase(configuration: new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create })) |
| 37 | +class Program |
19 | 38 | { |
20 | | - tx.Put(db, "hello"u8.ToArray(), "world"u8.ToArray()); |
21 | | - tx.Commit(); |
| 39 | + static void Main() |
| 40 | + { |
| 41 | + // Specify the path to the database environment |
| 42 | + using var env = new LightningEnvironment("path_to_your_database"); |
| 43 | + env.Open(); |
| 44 | + |
| 45 | + // Begin a transaction and open (or create) a database |
| 46 | + using (var tx = env.BeginTransaction()) |
| 47 | + using (var db = tx.OpenDatabase(configuration: new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create })) |
| 48 | + { |
| 49 | + // Put a key-value pair into the database |
| 50 | + tx.Put(db, UTF8.GetBytes("hello"), UTF8.GetBytes("world")); |
| 51 | + tx.Commit(); |
| 52 | + } |
| 53 | + |
| 54 | + // Begin a read-only transaction to retrieve the value |
| 55 | + using (var tx = env.BeginTransaction(TransactionBeginFlags.ReadOnly)) |
| 56 | + using (var db = tx.OpenDatabase()) |
| 57 | + { |
| 58 | + var (resultCode, key, value) = tx.Get(db, Encoding.UTF8.GetBytes("hello")); |
| 59 | + if (resultCode == MDBResultCode.Success) |
| 60 | + { |
| 61 | + Console.WriteLine($"{UTF8.GetString(key)}: {UTF8.GetString(value)}"); |
| 62 | + } |
| 63 | + else |
| 64 | + { |
| 65 | + Console.WriteLine("Key not found."); |
| 66 | + } |
| 67 | + } |
| 68 | + } |
22 | 69 | } |
23 | | -using (var tx = env.BeginTransaction(TransactionBeginFlags.ReadOnly)) |
24 | | -using (var db = tx.OpenDatabase()) |
| 70 | +``` |
| 71 | + |
| 72 | +In this example: |
| 73 | + |
| 74 | +- We create a new LMDB environment at the specified path. |
| 75 | +- We open a database within a transaction, inserting the key-value pair ("hello", "world"). |
| 76 | +- We commit the transaction to save the changes. |
| 77 | +- We then start a read-only transaction to retrieve and display the value associated with the key "hello". |
| 78 | + |
| 79 | +## Handling Multiple Values for the Same Key |
| 80 | + |
| 81 | +LMDB supports storing multiple values for a single key when the database is configured with the `Dupsort` flag. Here's how you can work with duplicate keys and use the cursor's `NextDuplicate` function: |
| 82 | + |
| 83 | +```csharp |
| 84 | +using System; |
| 85 | +using System.Text; |
| 86 | +using LightningDB; |
| 87 | + |
| 88 | +class Program |
25 | 89 | { |
26 | | - var (resultCode, key, value) = tx.Get(db, "hello"u8.ToArray()); |
27 | | - Console.WriteLine($"{Encoding.UTF8.GetString(key.AsSpan())} {Encoding.UTF8.GetString(value.AsSpan())}"); |
| 90 | + static void Main() |
| 91 | + { |
| 92 | + using var env = new LightningEnvironment("path_to_your_database"); |
| 93 | + env.Open(); |
| 94 | + |
| 95 | + // Configure the database to support duplicate keys |
| 96 | + var dbConfig = new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create | DatabaseOpenFlags.DuplicatesSort }; |
| 97 | + |
| 98 | + // Begin a transaction and open the database |
| 99 | + using (var tx = env.BeginTransaction()) |
| 100 | + using (var db = tx.OpenDatabase(configuration: dbConfig)) |
| 101 | + { |
| 102 | + var key = Encoding.UTF8.GetBytes("fruit"); |
| 103 | + var value1 = Encoding.UTF8.GetBytes("apple"); |
| 104 | + var value2 = Encoding.UTF8.GetBytes("cherry"); |
| 105 | + var value3 = Encoding.UTF8.GetBytes("banana"); |
| 106 | + |
| 107 | + // Insert multiple values for the same key |
| 108 | + tx.Put(db, key, value1); |
| 109 | + tx.Put(db, key, value2); |
| 110 | + tx.Put(db, key, value3); |
| 111 | + tx.Commit(); |
| 112 | + } |
| 113 | + |
| 114 | + // Begin a read-only transaction to retrieve the values |
| 115 | + using (var tx = env.BeginTransaction(TransactionBeginFlags.ReadOnly)) |
| 116 | + using (var db = tx.OpenDatabase()) |
| 117 | + using (var cursor = tx.CreateCursor(db)) |
| 118 | + { |
| 119 | + var key = Encoding.UTF8.GetBytes("fruit"); |
| 120 | + |
| 121 | + // Position the cursor at the first occurrence of the key |
| 122 | + var result = cursor.Set(key); |
| 123 | + if(result == MDBResultCode.Success) |
| 124 | + { |
| 125 | + do |
| 126 | + { |
| 127 | + var current = cursor.GetCurrent(); |
| 128 | + var currentKey = current.key.AsSpan(); |
| 129 | + var currentValue = current.value.AsSpan(); |
| 130 | + Console.WriteLine($"{UTF8.GetString(currentKey)}: {UTF8.GetString(currentValue)}"); |
| 131 | + } |
| 132 | + // Move to the next duplicate value |
| 133 | + while (cursor.NextDuplicate().resultCode == MDBResultCode.Success); |
| 134 | + } |
| 135 | + else |
| 136 | + { |
| 137 | + Console.WriteLine("Key not found."); |
| 138 | + } |
| 139 | + |
| 140 | + //Or even simpler |
| 141 | + var values = cursor.AllValuesFor(key); |
| 142 | + foreach(var value in values) |
| 143 | + { |
| 144 | + Console.WriteLine($"fruit: {Encoding.UTF8.GetString(value.AsSpan())}"); |
| 145 | + } |
| 146 | + } |
| 147 | + } |
28 | 148 | } |
29 | 149 | ``` |
30 | 150 |
|
31 | | -More examples can be found in the unit tests. |
| 151 | +In this example: |
| 152 | + |
| 153 | +- We configure the database with the `DupSort` flag to allow multiple values for a single key. |
| 154 | +- We insert three different values ("apple", "cherry", "banana") under the same key "fruit". |
| 155 | +- Using a cursor, we iterate over all values associated with the key "fruit" by moving to the next duplicate entry and see the values retrieved are ordered. |
| 156 | +- Then we demonstrate doing the same thing with IEnumerable instead. |
| 157 | + |
| 158 | +## Additional Resources |
32 | 159 |
|
33 | | -<a href="http://lmdb.tech/doc" target="_blank">Official LMDB API docs</a> |
| 160 | +For more detailed examples and advanced usage, refer to the unit tests in the [Lightning.NET repository](https://github.com/CoreyKaylor/Lightning.NET). |
34 | 161 |
|
35 | | -Library is available from NuGet: https://www.nuget.org/packages/LightningDB/ |
| 162 | +The official <a href="http://lmdb.tech/doc" target="_blank">Official LMDB API documentation</a> |
| 163 | +is also a valuable resource for understanding the underlying database engine. |
0 commit comments