GETTING STARTED

Your first persistent tree

Build a small C# application that writes records, reads them back, and scans keys in order. Then reopen the same data directory.

One package

ZoneTree runs inside your .NET process.

One directory

Open existing data or create a new tree.

Ordered keys

Read a single record or scan a range.

1. Create a console app

You need a .NET SDK installed. From a terminal, create a project and add the package:

dotnet new console -n ZoneTreeQuickstart
cd ZoneTreeQuickstart
dotnet add package ZoneTree

The example uses int keys and string values. ZoneTree supplies the comparer and serializers for these types.

2. Replace Program.cs

Paste this complete program into Program.cs:

using ZoneTree;

using var tree = new ZoneTreeFactory<int, string>()
    .SetDataDirectory("data/getting-started")
    .OpenOrCreate();
using var maintainer = tree.CreateMaintainer();

tree.Upsert(10, "Ada");
tree.Upsert(20, "Grace");
tree.Upsert(30, "Linus");

if (tree.TryGet(20, out var name))
    Console.WriteLine($"Read 20: {name}");

using var iterator = tree.CreateIterator();
iterator.Seek(10);

while (iterator.Next())
{
    if (iterator.CurrentKey >= 30)
        break;

    Console.WriteLine($"{iterator.CurrentKey}: {iterator.CurrentValue}");
}

tree.TryDelete(30, out _);
Console.WriteLine($"Contains 30: {tree.ContainsKey(30)}");
Keep the tree and its maintainer together

The maintainer schedules background merges and cleans inactive read caches. Keep it alive while the tree is in use. The using declarations dispose the iterator, maintainer, and tree in reverse order.

3. Run and inspect the result

dotnet run

With a fresh data directory, the output is:

Read 20: Grace
10: Ada
20: Grace
Contains 30: False

Here is what the program does:

Operation What to expect
OpenOrCreate() Creates the tree on the first run and opens it on later runs.
Upsert(key, value) Inserts a key or replaces its current value. Repeating the sample updates the same keys.
TryGet(20, out name) Returns true and the latest live value for key 20.
Seek(10) followed by Next() Starts at the first key greater than or equal to 10. The upper-bound check makes the scan [10, 30).
TryDelete(30, out _) Writes a deletion marker when the key exists. Later ordinary reads hide the deleted record.

The path is relative to the application's working directory. Keep that working directory unchanged when running the example again.

4. Open the persisted data

To read without writing the sample records again, replace Program.cs with:

using ZoneTree;

using var tree = new ZoneTreeFactory<int, string>()
    .SetDataDirectory("data/getting-started")
    .Open();
using var maintainer = tree.CreateMaintainer();

if (tree.TryGet(20, out var name))
    Console.WriteLine($"Persisted 20: {name}");

Run dotnet run from the same project directory. It prints Persisted 20: Grace. Open() requires existing data, so a path mistake fails instead of silently creating another tree.

Persistence and crash recovery

This example uses the default WAL configuration. A normal close-and-reopen demonstrates persistence; it does not establish what survives a process or machine failure. Read WAL modes to choose the durability boundary your application needs.

Further reading

Continue with one of these guides, or browse the Usage overview to compare reads, writes, atomic operations, transactions, scans, and maintenance.