ZoneTree 1.1.7
Prefix ReservedSee the version list below for details.
dotnet add package ZoneTree --version 1.1.7
NuGet\Install-Package ZoneTree -Version 1.1.7
<PackageReference Include="ZoneTree" Version="1.1.7" />
paket add ZoneTree --version 1.1.7
#r "nuget: ZoneTree, 1.1.7"
// Install ZoneTree as a Cake Addin #addin nuget:?package=ZoneTree&version=1.1.7 // Install ZoneTree as a Cake Tool #tool nuget:?package=ZoneTree&version=1.1.7
ZoneTree
ZoneTree is a persistent, high-performance, transactional, and ACID-compliant key-value database for .NET. It can operate in memory or on disk. (Optimized for SSDs)
ZoneTree is a lightweight, transactional and high-performance LSM Tree for .NET.
It is four times faster than Facebook's RocksDB.
Why ZoneTree?
- It is pure C#.
- It is fast. See benchmark below.
- Your data is protected against crashes / power cuts.
- Supports transactional and non-transactional access with blazing speeds and ACID guarantees.
- You can embed your database into your assembly. Therefore, you don't have to pay the cost of maintaining/shipping another database product along with yours.
How fast is it?
Insert Benchmarks | 1M | 2M | 3M | 10M |
---|---|---|---|---|
int-int ZoneTree lazy WAL | 1024 ms | 1828 ms | 2987 ms | 9852 ms |
int-int ZoneTree compressed-immediate WAL | 1678 ms | 3034 ms | 4646 ms | 15002 ms |
int-int ZoneTree immediate WAL | 3410 ms | 7297 ms | 10546 ms | 35151 ms |
str-str ZoneTree lazy WAL | 2192 ms | 4037 ms | 5924 ms | 19093 ms |
str-str ZoneTree compressed-immediate WAL | 2888 ms | 5087 ms | 7498 ms | 26188 ms |
str-str ZoneTree immediate WAL | 4649 ms | 9075 ms | 13774 ms | 47011 ms |
int-int RocksDb | NOT SUPPORTED | |||
str-str RocksDb immediate WAL | NOT SUPPORTED | |||
str-str RocksDb compressed-immediate WAL | 8215 ms | 16146 ms | 23760 ms | 72491 ms |
Benchmark Configuration:
DiskCompressionBlockSize = 1024 * 1024 * 1; // 1MB
WALCompressionBlockSize = 1024 * 1024; // 1 MB
DiskSegmentMode = DiskSegmentMode.MultipleDiskSegments;
ZoneTree offers 3 WAL modes to let you make a flexible tradeoff.
The Immediate mode provides maximum durability but slower write speed. In case of a crash/power cut, the immediate mode ensures that the inserted data is not lost. RocksDb does not have immediate WAL mode. It has a WAL mode similar to the CompressedImmediate mode. (reference:http://rocksdb.org/blog/2017/08/25/flushwal.html)
The CompressedImmediate mode provides faster write speed but less durability. Compression requires chunks to be filled before appending them into the WAL file. It is possible to enable a periodic job to persist decompressed tail records into a separate location in a specified interval. See IWriteAheadLogProvider options for more details.
The Lazy mode provides faster write speed but less durability. Log entries are queued to be written in a separate thread. Lazy mode uses compression in WAL files and provides immediate tail record persistence.
Environment:
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
Intel Core i7-6850K CPU 3.60GHz (Skylake), 1 CPU, 12 logical and 6 physical cores
64 GB DDR4 Memory
SSD: Samsung SSD 850 EVO 1TB
Config: 1M mutable segment size, 2M readonly segments merge-threshold
How to use ZoneTree?
The following sample demonstrates creating a database.
var dataPath = "data/mydatabase";
using var zoneTree = new ZoneTreeFactory<int, string>()
.SetComparer(new Int32ComparerAscending())
.SetDataDirectory(dataPath)
.SetKeySerializer(new Int32Serializer())
.SetValueSerializer(new Utf8StringSerializer())
.OpenOrCreate();
// atomic (thread-safe) on single mutable-segment.
zoneTree.Upsert(39, "Hello Zone Tree!");
// atomic across all segments
zoneTree.TryAtomicAddOrUpdate(39, "a", (x) => x + "b");
How to maintain LSM Tree?
Big LSM Trees require maintenance tasks. ZoneTree provides the IZoneTreeMaintenance interface to give you full power on maintenance tasks. It also comes with a default maintainer to let you focus on your business logic without wasting time with LSM details. You can start using the default maintainer like in the following sample code. Note: For small data you don't need a maintainer.
var dataPath = "data/mydatabase";
// 1. Create your ZoneTree
using var zoneTree = new ZoneTreeFactory<int, string>()
.SetComparer(new Int32ComparerAscending())
.SetDataDirectory(dataPath)
.SetKeySerializer(new Int32Serializer())
.SetValueSerializer(new Utf8StringSerializer())
.OpenOrCreate();
using var maintainer = new BasicZoneTreeMaintainer<int, string>(zoneTree);
// 2. Read/Write data
zoneTree.Upsert(39, "Hello ZoneTree!");
// 3. Complete maintainer running tasks.
maintainer.CompleteRunningTasks();
How to delete keys?
In LSM trees, the deletions are handled by upserting key/value with deleted flag. Later on, during the compaction stage, the actual deletion happens. ZoneTree does not implement this flag format by default. It lets the user to define the suitable deletion flag themselves. For example, the deletion flag might be defined by user as -1 for int values. If user wants to use any int value as a valid record, then the value-type should be changed. For example, one can define the following struct and use this type as a value-type.
[StructLayout(LayoutKind.Sequential)]
struct MyDeletableValueType {
int Number;
bool IsDeleted;
}
You can micro-manage the tree size with ZoneTree. The following sample shows how to configure the deletion markers for your database.
using var zoneTree = new ZoneTreeFactory<int, int>()
// Additional stuff goes here
.SetIsValueDeletedDelegate((in int x) => x == -1)
.SetMarkValueDeletedDelegate((ref int x) => x = -1)
.OpenOrCreate();
or
using var zoneTree = new ZoneTreeFactory<int, MyDeletableValueType>()
// Additional stuff goes here
.SetIsValueDeletedDelegate((in MyDeletableValueType x) => x.IsDeleted)
.SetMarkValueDeletedDelegate((ref MyDeletableValueType x) => x.IsDeleted = true)
.OpenOrCreate();
If you forget to provide the deletion marker delegates, you can never delete the record from your database.
How to iterate over data?
Iteration is possible in both directions, forward and backward. Unlike other LSM tree implementations, iteration performance is equal in both directions. The following sample shows how to do the iteration.
using var zoneTree = new ZoneTreeFactory<int, int>()
// Additional stuff goes here
.OpenOrCreate();
using var iterator = zoneTree.CreateIterator();
while(iterator.Next()) {
var key = iterator.CurrentKey;
var value = iterator.CurrentValue;
}
using var reverseIterator = zoneTree.CreateReverseIterator();
while(reverseIterator.Next()) {
var key = reverseIterator.CurrentKey;
var value = reverseIterator.CurrentValue;
}
How to iterate starting with a key (Seekable Iterator)?
ZoneTreeIterator provides Seek() method to jump into any record with in O(log(n)) complexity. That is useful for doing prefix search with forward-iterator or with backward-iterator.
using var zoneTree = new ZoneTreeFactory<string, int>()
// Additional stuff goes here
.OpenOrCreate();
using var iterator = zoneTree.CreateIterator();
// iterator jumps into the first record starting with "SomePrefix" in O(log(n)) complexity.
iterator.Seek("SomePrefix");
//iterator.Next() complexity is O(1)
while(iterator.Next()) {
var key = iterator.CurrentKey;
var value = iterator.CurrentValue;
}
Transaction Support
ZoneTree supports Optimistic Transactions. It is proud to announce that the ZoneTree is ACID-compliant. Of course, you can use non-transactional API for the scenarios where eventual consistency is sufficient.
ZoneTree supports 3 way of doing transactions.
- Fluent Transactions with ready to use retry capability.
- Classical Transaction API.
- Exceptionless Transaction API.
The following sample shows how to do the transactions with ZoneTree Fluent Transaction API.
using var zoneTree = new ZoneTreeFactory<int, int>()
// Additional stuff goes here
.OpenOrCreateTransactional();
using var transaction =
zoneTree
.BeginFluentTransaction()
.Do((tx) => zoneTree.UpsertNoThrow(tx, 3, 9))
.Do((tx) =>
{
if (zoneTree.TryGetNoThrow(tx, 3, out var value).IsAborted)
return TransactionResult.Aborted();
if (zoneTree.UpsertNoThrow(tx, 3, 21).IsAborted)
return TransactionResult.Aborted();
return TransactionResult.Success();
})
.SetRetryCountForPendingTransactions(100)
.SetRetryCountForAbortedTransactions(10);
await transaction.CommitAsync();
The following sample shows traditional way of doing transactions with ZoneTree.
using var zoneTree = new ZoneTreeFactory<int, int>()
// Additional stuff goes here
.OpenOrCreateTransactional();
try
{
var txId = zoneTree.BeginTransaction();
zoneTree.TryGet(txId, 3, out var value);
zoneTree.Upsert(txId, 3, 9);
var result = zoneTree.Prepare(txId);
while (result.IsPendingTransactions) {
Thread.Sleep(100);
result = zoneTree.Prepare(txId);
}
zoneTree.Commit(txId);
}
catch(TransactionAbortedException e)
{
//retry or cancel
}
Features
ZoneTree Features |
---|
Works with .NET primitives, structs and classes. |
High Speed and Low Memory consumption. |
Crash Resilience |
Optimum disk space utilization. |
WAL and DiskSegment data compression. |
Very fast load/unload. |
Standard read/upsert/delete functions. |
Optimistic Transaction Support |
Atomic Read Modify Update |
Can work in memory. |
Can work with any disk device including cloud devices. |
Supports optimistic transactions. |
Supports Atomicity, Consistency, Isolation, Durability. |
Supports Read Committed Isolation. |
Immediate and Lazy modes for write ahead log. |
Audit support with incremental transaction log backup. |
Live backup. |
Configurable amount of data that can stay in memory. |
Partially (with sparse arrays) or completely load/unload data on disk to/from memory. |
Forward/Backward iteration. |
Allow optional dirty reads. |
Embeddable. |
Optimized for SSDs. |
Exceptionless Transaction API. |
Fluent Transaction API with ready to use retry capabilities. |
Easy Maintenance. |
Configurable LSM merger. |
Transparent and simple implementation that reveals your database's internals. |
Fully open-source with unrestrictive MIT license. |
Transaction Log compaction. |
Analyze / control transactions. |
Concurrency Control with minimum overhead by novel separation of Concurrency Stamps and Data. |
TTL support. |
Use your custom serializer for keys and values. |
Use your custom comparer. |
MultipleDiskSegments Mode to enable dividing data files into configurable sized chunks. |
I need more information. Where can I find it?
I am going to write more detailed documentation as soon as possible.
I want to contribute. What can I do?
I appreciate any contribution to the project. These are the things I do think we need at the moment:
- Write tests / benchmarks.
- Write documentation.
- Convert documentation to a website using static site generators.
- Feature requests & bug fixes.
- Performance improvements.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- No dependencies.
NuGet packages (5)
Showing the top 5 NuGet packages that depend on ZoneTree:
Package | Downloads |
---|---|
DifferentialComputeDotNet.Core
Package Description |
|
ZoneTree.FullTextSearch
ZoneTree.FullTextSearch is an open-source library that extends ZoneTree to provide efficient full-text search capabilities. It offers a fast, embedded search engine suitable for applications that require high performance and do not rely on external databases. |
|
ManagedCode.ZoneTree.BlobFileSystem
Azure Blob FileSystem for ZoneTree |
|
ManagedCode.Database.ZoneTree
Repository for ZoneTree |
|
RickDotNet.FusionStore.Stores.ZoneTree
A FusionCache and ZoneTree inspired data store abstraction. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.8.4 | 42 | 11/14/2024 |
1.8.3 | 203 | 10/16/2024 |
1.8.2 | 297 | 9/7/2024 |
1.8.1 | 119 | 9/7/2024 |
1.8.0 | 126 | 9/1/2024 |
1.7.9 | 138 | 8/30/2024 |
1.7.8 | 103 | 8/30/2024 |
1.7.7 | 164 | 8/24/2024 |
1.7.6 | 168 | 8/17/2024 |
1.7.5 | 132 | 8/17/2024 |
1.7.4 | 129 | 8/11/2024 |
1.7.3 | 105 | 8/10/2024 |
1.7.2 | 116 | 7/19/2024 |
1.7.1 | 220 | 6/14/2024 |
1.7.0 | 1,975 | 12/12/2023 |
1.6.9 | 628 | 9/13/2023 |
1.6.8 | 134 | 9/13/2023 |
1.6.7 | 132 | 9/13/2023 |
1.6.6 | 183 | 8/18/2023 |
1.6.5 | 194 | 6/17/2023 |
1.6.4 | 138 | 6/16/2023 |
1.6.3 | 201 | 5/29/2023 |
1.6.2 | 16,869 | 5/26/2023 |
1.6.1 | 283 | 4/5/2023 |
1.6.0 | 1,897 | 1/14/2023 |
1.5.9 | 308 | 1/14/2023 |
1.5.8 | 1,000 | 11/20/2022 |
1.5.7 | 382 | 11/14/2022 |
1.5.6 | 352 | 11/13/2022 |
1.5.5 | 466 | 10/20/2022 |
1.5.2 | 496 | 9/14/2022 |
1.5.1 | 415 | 9/3/2022 |
1.5.0 | 416 | 9/2/2022 |
1.4.9 | 418 | 8/31/2022 |
1.4.8 | 381 | 8/30/2022 |
1.4.7 | 417 | 8/30/2022 |
1.4.6 | 426 | 8/29/2022 |
1.4.5 | 440 | 8/28/2022 |
1.4.4 | 608 | 8/27/2022 |
1.4.3 | 426 | 8/26/2022 |
1.4.2 | 419 | 8/26/2022 |
1.4.1 | 388 | 8/26/2022 |
1.4.0 | 418 | 8/25/2022 |
1.3.9 | 404 | 8/25/2022 |
1.3.8 | 422 | 8/24/2022 |
1.3.7 | 684 | 8/23/2022 |
1.3.6 | 403 | 8/22/2022 |
1.3.5 | 425 | 8/22/2022 |
1.3.4 | 418 | 8/21/2022 |
1.3.3 | 405 | 8/18/2022 |
1.3.2 | 434 | 8/17/2022 |
1.3.1 | 403 | 8/17/2022 |
1.3.0 | 416 | 8/17/2022 |
1.2.9 | 404 | 8/16/2022 |
1.2.8 | 397 | 8/15/2022 |
1.2.7 | 423 | 8/15/2022 |
1.2.6 | 413 | 8/13/2022 |
1.2.5 | 428 | 8/13/2022 |
1.2.4 | 413 | 8/13/2022 |
1.2.3 | 438 | 8/9/2022 |
1.2.2 | 393 | 8/9/2022 |
1.2.1 | 436 | 8/9/2022 |
1.2.0 | 455 | 8/8/2022 |
1.1.9 | 429 | 8/8/2022 |
1.1.8 | 419 | 8/8/2022 |
1.1.7 | 443 | 8/8/2022 |
1.1.6 | 406 | 8/7/2022 |
1.1.5 | 432 | 8/6/2022 |
1.1.4 | 416 | 8/6/2022 |
1.1.3 | 423 | 8/5/2022 |
1.1.2 | 431 | 8/5/2022 |
1.1.1 | 431 | 7/27/2022 |
1.1.0 | 435 | 7/27/2022 |
1.0.9 | 424 | 7/25/2022 |
1.0.8 | 410 | 7/24/2022 |
1.0.7 | 385 | 7/23/2022 |
1.0.6 | 423 | 7/20/2022 |
1.0.5 | 437 | 7/18/2022 |
1.0.4 | 436 | 7/11/2022 |
1.0.3 | 474 | 7/11/2022 |
1.0.2 | 465 | 7/11/2022 |
1.0.1 | 450 | 7/6/2022 |
1.0.0 | 449 | 7/6/2022 |