Stats
This guide shows how to inspect the state of a Vix KV database.
Use this page when you want to check live keys, tombstones, memory mode, recovery information, and sequence state.
Public header
#include <vix/kv/kv.hpp>
#include <vix/print.hpp>What stats are for
Stats help you observe what is happening inside a KV database.
Use stats() when you want to know:
- whether the database is open
- whether it is memory-only
- how many live keys exist
- how many tombstones exist
- the last sequence number
- how many WAL records were recovered after reopen
Basic stats
#include <vix/kv/kv.hpp>
#include <vix/print.hpp>
int main()
{
auto opened = vix::kv::open_memory();
if (opened.is_err())
{
vix::eprint(opened.error().message());
return 1;
}
auto kv = opened.move_value();
(void)kv.set({"a"}, "one");
(void)kv.set({"b"}, "two");
(void)kv.erase(vix::kv::KeyPath{"a"});
const auto stats = kv.stats();
vix::print("open =", stats.open ? "yes" : "no");
vix::print("memory only =", stats.memory_only ? "yes" : "no");
vix::print("live keys =", stats.key_count);
vix::print("tombstones =", stats.tombstone_count);
vix::print("last sequence =", stats.last_sequence);
(void)kv.close();
return 0;
}Run:
vix run main.cppExpected output:
open = yes
memory only = yes
live keys = 1
tombstones = 1
last sequence = 3Stats fields
| Field | Meaning |
|---|---|
open | Whether the database is currently open. |
memory_only | Whether the database is memory-only. |
key_count | Number of live keys. |
tombstone_count | Number of delete markers. |
last_sequence | Last applied operation sequence. |
wal_records_recovered | Number of WAL records recovered when opening a durable database. |
Live keys
Live keys are values currently visible to reads and lists.
const auto stats = kv.stats();
vix::print("live keys =", stats.key_count);Example:
#include <vix/kv/kv.hpp>
#include <vix/print.hpp>
int main()
{
auto opened = vix::kv::open_memory();
if (opened.is_err())
{
vix::eprint(opened.error().message());
return 1;
}
auto kv = opened.move_value();
(void)kv.set({"users", "1", "name"}, "Ada");
(void)kv.set({"users", "2", "name"}, "Grace");
const auto stats = kv.stats();
vix::print("live keys =", stats.key_count);
vix::print("size =", kv.size());
(void)kv.close();
return 0;
}Expected output:
live keys = 2
size = 2Tombstones
A tombstone represents a delete.
When you erase a key, the live key count decreases and the tombstone count increases.
auto erased = kv.erase(vix::kv::KeyPath{"users", "1", "name"});
if (erased.is_err())
{
vix::eprint(erased.error().message());
return 1;
}Then inspect stats:
const auto stats = kv.stats();
vix::print("live keys =", stats.key_count);
vix::print("tombstones =", stats.tombstone_count);Complete example:
#include <vix/kv/kv.hpp>
#include <vix/print.hpp>
int main()
{
auto opened = vix::kv::open_memory();
if (opened.is_err())
{
vix::eprint(opened.error().message());
return 1;
}
auto kv = opened.move_value();
(void)kv.set({"users", "1", "name"}, "Ada");
(void)kv.set({"users", "2", "name"}, "Grace");
auto erased = kv.erase(vix::kv::KeyPath{"users", "1", "name"});
if (erased.is_err())
{
vix::eprint(erased.error().message());
return 1;
}
const auto stats = kv.stats();
vix::print("live keys =", stats.key_count);
vix::print("tombstones =", stats.tombstone_count);
(void)kv.close();
return 0;
}Expected output:
live keys = 1
tombstones = 1Open state
Use stats.open or kv.is_open() to check whether the database is open.
const auto stats = kv.stats();
vix::print("open =", stats.open ? "yes" : "no");You can also use:
vix::print("open =", kv.is_open() ? "yes" : "no");Memory-only state
Use stats.memory_only to know whether the database is temporary.
const auto stats = kv.stats();
vix::print("memory only =", stats.memory_only ? "yes" : "no");Memory-only databases are useful for tests and temporary state.
auto opened = vix::kv::open_memory();Durable databases are backed by a filesystem path.
auto kv = vix::kv::open("data/app");Sequence state
last_sequence tracks the last applied operation sequence.
Each write or delete advances the operation history.
const auto stats = kv.stats();
vix::print("last sequence =", stats.last_sequence);Example:
#include <vix/kv/kv.hpp>
#include <vix/print.hpp>
int main()
{
auto opened = vix::kv::open_memory();
if (opened.is_err())
{
vix::eprint(opened.error().message());
return 1;
}
auto kv = opened.move_value();
(void)kv.set({"a"}, "one");
(void)kv.set({"b"}, "two");
(void)kv.erase(vix::kv::KeyPath{"a"});
const auto stats = kv.stats();
vix::print("last sequence =", stats.last_sequence);
(void)kv.close();
return 0;
}Expected output:
last sequence = 3Recovery stats
For durable databases, stats can show recovery information after reopening.
const auto stats = kv.stats();
vix::print("wal recovered =", stats.wal_records_recovered);
vix::print("last sequence =", stats.last_sequence);Example:
#include <vix/kv/kv.hpp>
#include <vix/print.hpp>
int main()
{
{
auto kv = vix::kv::open("data/recovery-stats");
kv.put("name", "Ada");
kv.put("theme", "dark");
(void)kv.flush();
(void)kv.close();
}
{
auto kv = vix::kv::open("data/recovery-stats");
const auto stats = kv.stats();
vix::print("wal recovered =", stats.wal_records_recovered);
vix::print("last sequence =", stats.last_sequence);
vix::print("live keys =", stats.key_count);
(void)kv.close();
}
return 0;
}Example output:
wal recovered = 2
last sequence = 2
live keys = 2Stats with list
list() returns live entries. stats() tells you about live entries and tombstones.
auto entries = kv.list({"users"});
if (entries.is_err())
{
vix::eprint(entries.error().message());
return 1;
}
const auto stats = kv.stats();
vix::print("listed users =", entries.value().size());
vix::print("live keys =", stats.key_count);
vix::print("tombstones =", stats.tombstone_count);Complete example:
#include <vix/kv/kv.hpp>
#include <vix/print.hpp>
int main()
{
auto opened = vix::kv::open_memory();
if (opened.is_err())
{
vix::eprint(opened.error().message());
return 1;
}
auto kv = opened.move_value();
(void)kv.set({"users", "1", "name"}, "Ada");
(void)kv.set({"users", "2", "name"}, "Grace");
(void)kv.set({"users", "3", "name"}, "Linus");
auto erased = kv.erase(vix::kv::KeyPath{"users", "3", "name"});
if (erased.is_err())
{
vix::eprint(erased.error().message());
return 1;
}
auto users = kv.list({"users"});
if (users.is_err())
{
vix::eprint(users.error().message());
return 1;
}
const auto stats = kv.stats();
vix::print("listed users =", users.value().size());
vix::print("live keys =", stats.key_count);
vix::print("tombstones =", stats.tombstone_count);
(void)kv.close();
return 0;
}Expected output:
listed users = 2
live keys = 2
tombstones = 1Stats and size
kv.size() returns the number of live keys. stats.key_count also represents live keys.
vix::print("size =", kv.size());
const auto stats = kv.stats();
vix::print("live keys =", stats.key_count);Example:
#include <vix/kv/kv.hpp>
#include <vix/print.hpp>
int main()
{
auto opened = vix::kv::open_memory();
if (opened.is_err())
{
vix::eprint(opened.error().message());
return 1;
}
auto kv = opened.move_value();
(void)kv.set({"a"}, "one");
(void)kv.set({"b"}, "two");
const auto stats = kv.stats();
vix::print("size =", kv.size());
vix::print("live keys =", stats.key_count);
(void)kv.close();
return 0;
}Expected output:
size = 2
live keys = 2Common workflows
Print basic stats
const auto stats = kv.stats();
vix::print("open =", stats.open ? "yes" : "no");
vix::print("memory only =", stats.memory_only ? "yes" : "no");
vix::print("live keys =", stats.key_count);
vix::print("tombstones =", stats.tombstone_count);
vix::print("last sequence =", stats.last_sequence);Check live key count
const auto stats = kv.stats();
if (stats.key_count == 0)
{
vix::print("database is empty");
}Check delete markers
const auto stats = kv.stats();
if (stats.tombstone_count > 0)
{
vix::print("database has tombstones");
}Check recovery
const auto stats = kv.stats();
vix::print("wal recovered =", stats.wal_records_recovered);Compare list and stats
auto users = kv.list({"users"});
if (users.is_ok())
{
const auto stats = kv.stats();
vix::print("users prefix =", users.value().size());
vix::print("all live keys =", stats.key_count);
}Common mistakes
Confusing live keys and tombstones
Live keys are readable values. Tombstones are delete markers.
const auto stats = kv.stats();
vix::print("live keys =", stats.key_count);
vix::print("tombstones =", stats.tombstone_count);Expecting deleted keys to appear in size
Deleted keys are not live keys.
vix::print("size =", kv.size());Use tombstones when you want to observe deletes.
const auto stats = kv.stats();
vix::print("tombstones =", stats.tombstone_count);Expecting memory-only stores to recover WAL records
Memory-only stores are temporary.
auto opened = vix::kv::open_memory();Recovery stats are most useful with durable databases.
auto kv = vix::kv::open("data/app");Reading stats before operations
Stats reflect the current state. If you read stats before writing, counts may be zero.
const auto before = kv.stats();
(void)kv.set({"a"}, "one");
const auto after = kv.stats();Treating stats as application data
Stats are for observability. Store application data with put or set.
kv.put("settings/theme", "dark");Best practices
Use stats() when debugging persistence and recovery. Use stats() after deletes to confirm tombstones. Use kv.size() when you only need the live key count. Use list(prefix) when you need the actual entries. Use wal_records_recovered to inspect durable reopen behavior.
Related pages
| Page | Purpose |
|---|---|
| Opening a database | Learn how to open memory and durable stores. |
| Keys | Learn how to structure keys and prefixes. |
| Values | Learn how to write, read, and delete values. |
| Persistence | Learn how values survive restart. |
| Recovery | Learn how recovered records and tombstones work. |
| API Reference | See the public KV API surface. |
Next step
Continue with the API reference.