Vix.cpp docs moved to vixcpp.com
Skip to content

Local Store

The Softadastra C++ SDK provides a local key/value store through softadastra::sdk::Client.

The local store is the first layer of the SDK. It lets an application write data locally, read it back, check if a key exists, remove values, and inspect the number of stored entries.

A local write does not require the network.

Include

cpp
#include <softadastra/sdk.hpp>

Basic local store example

Use ClientOptions::memory_only() or ClientOptions::local() for a memory-only local store.

cpp
#include <softadastra/sdk.hpp>

#include <iostream>

int main()
{
    using namespace softadastra::sdk;

    Client client{
        ClientOptions::memory_only("local-store-example")
    };

    const auto opened = client.open();

    if (opened.is_err())
    {
        std::cerr << "open failed: "
                  << opened.error().code_string()
                  << ": "
                  << opened.error().message()
                  << "\n";

        return 1;
    }

    const auto stored = client.put("hello", "world");

    if (stored.is_err())
    {
        std::cerr << "put failed: "
                  << stored.error().code_string()
                  << ": "
                  << stored.error().message()
                  << "\n";

        client.close();
        return 1;
    }

    const auto value = client.get("hello");

    if (value.is_err())
    {
        std::cerr << "get failed: "
                  << value.error().code_string()
                  << ": "
                  << value.error().message()
                  << "\n";

        client.close();
        return 1;
    }

    std::cout << "value: "
              << value.value().to_string()
              << "\n";

    client.close();

    return 0;
}

Expected output:

txt
value: world

Local mode

ClientOptions::local() is a developer-friendly alias for ClientOptions::memory_only().

cpp
auto options = softadastra::sdk::ClientOptions::local("node-1");

This mode keeps data in memory only.

txt
No WAL file
No restart recovery
Useful for tests, examples, and temporary data

For durable local data, use Persistent Store.

Keys

Keys identify values in the local store.

cpp
softadastra::sdk::Key key{"profile/name"};

A key must not be empty.

cpp
const auto saved = client.put("", "value");

if (saved.is_err())
{
    std::cerr << saved.error().code_string()
              << ": "
              << saved.error().message()
              << "\n";
}

Possible output:

txt
invalid_argument: key cannot be empty

You can use string keys directly:

cpp
client.put("profile/name", "Ada");
client.get("profile/name");
client.remove("profile/name");

Or explicit Key objects:

cpp
using namespace softadastra::sdk;

Key key = Key::from("profile/name");

client.put(key, Value::from_string("Ada"));

Values

Values are binary-safe payloads.

cpp
softadastra::sdk::Value value{"hello"};

The SDK stores values as bytes. It does not interpret the content.

A value can represent:

txt
text
JSON
metadata
binary data
application-specific payloads

Create a value from a string:

cpp
auto value = softadastra::sdk::Value::from_string("hello");

Read it back as a string:

cpp
std::cout << value.to_string() << "\n";

to_string() does not validate UTF-8. It simply converts the stored bytes to a std::string.

Store text data

cpp
const auto saved = client.put("profile/name", "Ada");

if (saved.is_err())
{
    return 1;
}

Read the value:

cpp
const auto name = client.get("profile/name");

if (name.is_ok())
{
    std::cout << name.value().to_string() << "\n";
}

Store JSON data

The SDK does not parse JSON automatically. It stores JSON as bytes.

cpp
const auto saved = client.put(
    "user/1",
    R"({"name":"Ada","language":"C++"})"
);

if (saved.is_err())
{
    return 1;
}

Read it back:

cpp
const auto user = client.get("user/1");

if (user.is_ok())
{
    std::cout << user.value().to_string() << "\n";
}

Store binary data

Use Value::from_bytes() when storing binary data.

cpp
#include <softadastra/sdk.hpp>

#include <cstdint>
#include <vector>

int main()
{
    using namespace softadastra::sdk;

    Client client{
        ClientOptions::memory_only("binary-example")
    };

    const auto opened = client.open();

    if (opened.is_err())
    {
        return 1;
    }

    std::vector<std::uint8_t> bytes{
        0x48,
        0x65,
        0x6c,
        0x6c,
        0x6f
    };

    const auto saved = client.put(
        Key::from("binary/hello"),
        Value::from_bytes(bytes)
    );

    if (saved.is_err())
    {
        client.close();
        return 1;
    }

    client.close();

    return 0;
}

Read a value

get() reads from the local store.

cpp
const auto value = client.get("hello");

if (value.is_err())
{
    std::cerr << value.error().code_string()
              << ": "
              << value.error().message()
              << "\n";

    return 1;
}

std::cout << value.value().to_string() << "\n";

If the key does not exist, the SDK returns:

txt
not_found: key not found

Check if a key exists

Use contains().

cpp
if (client.contains("hello"))
{
    std::cout << "key exists\n";
}

contains() returns false when:

txt
the client is closed
the key is empty
the key does not exist

Remove a value

Use remove().

cpp
const auto removed = client.remove("hello");

if (removed.is_err())
{
    std::cerr << removed.error().code_string()
              << ": "
              << removed.error().message()
              << "\n";

    return 1;
}

After removing the value:

cpp
if (!client.contains("hello"))
{
    std::cout << "removed\n";
}

Like put(), remove() is submitted through the synchronization pipeline.

Store size

Use size() to get the number of entries in the local store.

cpp
std::cout << "entries: "
          << client.size()
          << "\n";

Use empty() to check if the store is empty.

cpp
if (client.empty())
{
    std::cout << "store is empty\n";
}

When the client is closed, size() returns 0.

Local writes and sync

A local write is accepted locally first.

cpp
client.put("message", "hello");

Internally, the SDK creates a local operation and submits it to the synchronization pipeline.

That means local storage and synchronization are connected:

txt
client.put()

local operation

local store

sync pipeline

outbox / queued operation

The application can inspect this with sync_state().

cpp
const auto state = client.sync_state();

if (state.is_ok())
{
    std::cout << "outbox: "
              << state.value().outbox_size()
              << "\n";

    std::cout << "queued: "
              << state.value().queued_count()
              << "\n";
}

Complete example

cpp
#include <softadastra/sdk.hpp>

#include <iostream>

int main()
{
    using namespace softadastra::sdk;

    Client client{
        ClientOptions::memory_only("example-local-store")
    };

    const auto opened = client.open();

    if (opened.is_err())
    {
        std::cerr << "open failed: "
                  << opened.error().code_string()
                  << ": "
                  << opened.error().message()
                  << "\n";

        return 1;
    }

    const auto stored = client.put("hello", "world");

    if (stored.is_err())
    {
        std::cerr << "put failed: "
                  << stored.error().code_string()
                  << ": "
                  << stored.error().message()
                  << "\n";

        client.close();
        return 1;
    }

    const auto value = client.get("hello");

    if (value.is_err())
    {
        std::cerr << "get failed: "
                  << value.error().code_string()
                  << ": "
                  << value.error().message()
                  << "\n";

        client.close();
        return 1;
    }

    std::cout << "key   : hello\n";

    std::cout << "value : "
              << value.value().to_string()
              << "\n";

    std::cout << "entries: "
              << client.size()
              << "\n";

    client.close();

    return 0;
}

Summary

Use the local store API to:

txt
write values with put()
read values with get()
remove values with remove()
check keys with contains()
inspect entry count with size()
check emptiness with empty()

Use ClientOptions::memory_only() or ClientOptions::local() for temporary in-memory storage.

Use ClientOptions::persistent() when local data must survive restarts.

Next, continue with Persistent Store.

Released under the Apache License 2.0.