ExDataSketch.Storage.CubDB (ExDataSketch v0.9.0)

Copy Markdown View Source

CubDB-backed persistence for sketches.

Stores serialized EXSK v2 frames in a CubDB key-value store. CubDB provides disk-backed, MVCC-based storage with atomic transactions.

Dependency

This module requires the :cubdb package. If CubDB is not available, calls will raise a clear error directing you to add the dependency.

Concurrency

  • CubDB supports concurrent reads via MVCC.
  • merge/3 uses a CubDB transaction for atomicity.

Non-executable examples

The examples below use CubDB.start_link/1 which requires the :cubdb dependency. They are included for documentation purposes and will not run in the standard test suite.

Examples

# Start a CubDB database (application concern)
{:ok, db} = CubDB.start_link(data_dir: "/tmp/sketches")

# Save a sketch
:ok = ExDataSketch.Storage.CubDB.save(sketch, db, "cardinality:2024-01")

# Load a sketch
{:ok, sketch} = ExDataSketch.Storage.CubDB.load(ExDataSketch.HLL, db, "cardinality:2024-01")

# Atomic merge
:ok = ExDataSketch.Storage.CubDB.merge(partial, db, "cardinality:2024-01")

Summary

Functions

Returns whether CubDB is available at runtime.

Deletes a sketch from the CubDB database by key.

Loads a sketch from the CubDB database by key.

Atomically merges a sketch into the persisted value at the given key.

Persists a sketch under the given key in the CubDB database.

Functions

cubdb_available?()

@spec cubdb_available?() :: boolean()

Returns whether CubDB is available at runtime.

Examples

iex> is_boolean(ExDataSketch.Storage.CubDB.cubdb_available?())
true

delete(db, key)

@spec delete(pid() | atom(), ExDataSketch.Storage.key()) :: :ok

Deletes a sketch from the CubDB database by key.

Arguments

  • db -- the CubDB process.
  • key -- the key to delete.

Returns

:ok always (even if the key did not exist).

Examples

iex> {:ok, db} = CubDB.start_link(data_dir: System.tmp_dir!())
iex> sketch = ExDataSketch.HLL.new(p: 10)
iex> ExDataSketch.Storage.CubDB.save(sketch, db, "hll:test")
:ok
iex> ExDataSketch.Storage.CubDB.delete(db, "hll:test")
:ok
iex> ExDataSketch.Storage.CubDB.load(ExDataSketch.HLL, db, "hll:test")
{:error, :not_found}
iex> GenServer.stop(db, :normal)
:ok

load(sketch_module, db, key)

@spec load(module(), pid() | atom(), ExDataSketch.Storage.key()) ::
  {:ok, struct()} | {:error, :not_found | term()}

Loads a sketch from the CubDB database by key.

The binary value is deserialized using the given sketch module's deserialize/1 function.

Arguments

  • sketch_module -- the sketch module atom (e.g., ExDataSketch.HLL).
  • db -- the CubDB process.
  • key -- the key to look up.

Returns

  • {:ok, sketch} on success.
  • {:error, :not_found} if the key does not exist.
  • {:error, %DeserializationError{}} if the stored binary is corrupted.
  • {:error, reason} on other deserialization failures.

Raises

Examples

iex> {:ok, db} = CubDB.start_link(data_dir: System.tmp_dir!())
iex> sketch = ExDataSketch.HLL.new(p: 10) |> ExDataSketch.HLL.update("a")
iex> ExDataSketch.Storage.CubDB.save(sketch, db, "hll:test")
:ok
iex> {:ok, loaded} = ExDataSketch.Storage.CubDB.load(ExDataSketch.HLL, db, "hll:test")
iex> ExDataSketch.HLL.estimate(loaded) > 0.0
true
iex> ExDataSketch.Storage.CubDB.load(ExDataSketch.HLL, db, "nonexistent")
{:error, :not_found}
iex> GenServer.stop(db, :normal)
:ok

merge(sketch, db, key)

@spec merge(struct(), pid() | atom(), ExDataSketch.Storage.key()) :: :ok

Atomically merges a sketch into the persisted value at the given key.

Uses a CubDB transaction for atomicity. If no sketch exists at the key, this is equivalent to save/3.

Arguments

  • sketch -- the sketch to merge.
  • db -- the CubDB process.
  • key -- the key whose persisted sketch to merge into.

Returns

:ok on success.

Raises

Examples

iex> {:ok, db} = CubDB.start_link(data_dir: System.tmp_dir!())
iex> sketch_a = ExDataSketch.HLL.new(p: 10) |> ExDataSketch.HLL.update("a")
iex> ExDataSketch.Storage.CubDB.save(sketch_a, db, "hll:test")
:ok
iex> sketch_b = ExDataSketch.HLL.new(p: 10) |> ExDataSketch.HLL.update("b")
iex> ExDataSketch.Storage.CubDB.merge(sketch_b, db, "hll:test")
:ok
iex> {:ok, merged} = ExDataSketch.Storage.CubDB.load(ExDataSketch.HLL, db, "hll:test")
iex> ExDataSketch.HLL.estimate(merged) >= 1.9
true
iex> GenServer.stop(db, :normal)
:ok

save(sketch, db, key)

@spec save(struct(), pid() | atom(), ExDataSketch.Storage.key()) :: :ok

Persists a sketch under the given key in the CubDB database.

The sketch is serialized to an EXSK v2 binary frame before storage.

Arguments

  • sketch -- a sketch struct.
  • db -- the CubDB process (pid or registered name).
  • key -- the key under which to store the sketch.

Returns

:ok on success.

Raises

Examples

iex> {:ok, db} = CubDB.start_link(data_dir: System.tmp_dir!())
iex> sketch = ExDataSketch.HLL.new(p: 10) |> ExDataSketch.HLL.update("a")
iex> ExDataSketch.Storage.CubDB.save(sketch, db, "hll:test")
:ok
iex> GenServer.stop(db, :normal)
:ok