Goblin (Goblin v0.10.0)

Copy Markdown View Source

A lightweight, embedded, LSM-tree database for Elixir.

Goblin is a persistent key-value store with ACID transactions, crash recovery, and automatic background compaction. It runs inside your application's supervision tree.

Starting a database

{:ok, db} = Goblin.start_link(
  name: MyApp.DB,
  data_dir: "/path/to/db"
)

Basic operations

Goblin.put(db, :alice, "Alice")
Goblin.get(db, :alice)
# => "Alice"

Goblin.remove(db, :alice)
Goblin.get(db, :alice)
# => nil

Batch operations

Goblin.put_multi(db, [{:alice, "Alice"}, {:bob, "Bob"}])

Goblin.get_multi(db, [:alice, :bob])
# => [{:alice, "Alice"}, {:bob, "Bob"}]

Transactions

Goblin.transaction(db, fn tx ->
  counter = Goblin.Tx.get(tx, :counter, default: 0)

  tx
  |> Goblin.Tx.put(:counter, counter + 1)
  |> Goblin.Tx.commit()
end)
# => :ok

See start_link/1 for configuration options.

Summary

Functions

Returns whether background compaction is currently running.

Exports a snapshot of the database as a .tar.gz archive.

Returns whether a memory-to-disk flush is currently running.

Retrieves the value associated with a key.

Retrieves values for multiple keys in a single read.

Writes a key-value pair to the database.

Writes multiple key-value pairs in a single transaction.

Performs a read-only transaction.

Removes a key from the database.

Removes multiple keys from the database in a single transaction.

Returns a stream of key-value pairs, optionally bounded by a range. Captures snapshots at enumeration.

Starts the database, see start_link/1 for more details.

Starts the database.

Executes a read-write transaction.

Functions

child_spec(opts)

@spec child_spec(keyword()) :: Supervisor.child_spec()

compacting?(db, opts \\ [])

@spec compacting?(
  :gen_statem.server_ref(),
  keyword()
) :: boolean()

Returns whether background compaction is currently running.

export(db, export_dir, opts \\ [])

@spec export(:gen_statem.server_ref(), Path.t(), keyword()) ::
  {:ok, Path.t()} | {:error, term()}

Exports a snapshot of the database as a .tar.gz archive.

The archive can be unpacked and used as the data_dir for a new database instance, acting as a backup.

The export is run inside the server, thus blocking file deletion and writes until completed.

Parameters

  • db - The database server (PID or registered name)
  • export_dir - Directory to place the exported .tar.gz file

Returns

  • {:ok, export_path} - Path to the created archive
  • {:error, reason} - If an error occurred

Examples

Goblin.export(db, "/backups")
# => {:ok, "/backups/goblin_20260220T120000Z.tar.gz"}

flushing?(db, opts \\ [])

@spec flushing?(
  :gen_statem.server_ref(),
  keyword()
) :: boolean()

Returns whether a memory-to-disk flush is currently running.

get(db, key, opts \\ [])

Retrieves the value associated with a key.

Returns the default value if the key is not found.

Parameters

  • db - The database server (PID or registered name)
  • key - The key to look up
  • opts - A keyword list with the following options (default: []):
    • :tag - Tag the key is namespaced under
    • :default - Value to return if key is not found (default: nil)

Returns

  • The value associated with the key, or default if not found

Examples

Goblin.get(db, :alice)
# => "Alice"

Goblin.get(db, :nonexistent)
# => nil

Goblin.get(db, :nonexistent, default: :not_found)
# => :not_found

Goblin.get(db, :alice, tag: :admins)
# => "Alice"

get_multi(db, keys, opts \\ [])

Retrieves values for multiple keys in a single read.

Keys not found in the database are excluded from the result.

Parameters

  • db - The database server (PID or registered name)
  • keys - A list of keys to look up
  • opts - A keyword list with the following options (default: []):
    • :tag - Tag the keys are namespaced under

Returns

  • A list of {key, value} tuples for keys found, in unspecified order

Examples

Goblin.get_multi(db, [:alice, :bob])
# => [{:alice, "Alice"}, {:bob, "Bob"}]

Goblin.get_multi(db, [:alice, :nonexistent])
# => [{:alice, "Alice"}]

idle(arg1, down, db)

occupied(arg1, down, db)

put(db, key, val, opts \\ [])

Writes a key-value pair to the database.

Parameters

  • db - The database server (PID or registered name)
  • key - Any Elixir term to use as the key
  • value - Any Elixir term to be associated with key
  • opts - A keyword list with the following options (default: []):
    • :tag - Tag to namespace the key under
    • :timeout - Timeout (in milliseconds) for the calls (default: 5000)

Returns

  • :ok

Examples

Goblin.put(db, :alice, "Alice")
# => :ok

Goblin.put(db, :alice, "Alice", tag: :admins)
# => :ok

put_multi(db, pairs, opts \\ [])

Writes multiple key-value pairs in a single transaction.

Parameters

  • db - The database server (PID or registered name)
  • pairs - A list of {key, value} tuples
  • opts - A keyword list with the following options (default: []):
    • :tag - Tag to namespace the keys under
    • :timeout - Timeout (in milliseconds) for the calls (default: 5000)

Returns

  • :ok

Examples

Goblin.put_multi(db, [{:alice, "Alice"}, {:bob, "Bob"}, {:charlie, "Charlie"}])
# => :ok

read(db, callback)

Performs a read-only transaction.

A snapshot is taken to provide a consistent mvcc of the database. Multiple readers run concurrently without blocking each other. Attempting to write within a read transaction raises.

Parameters

  • db - The database server (PID or registered name)
  • callback - A function that takes a Goblin.Tx.t() struct

Returns

  • The return value of callback

Examples

Goblin.read(db, fn tx ->
  alice = Goblin.Tx.get(tx, :alice)
  bob = Goblin.Tx.get(tx, :bob)
  {alice, bob}
end)
# => {"Alice", "Bob"}

remove(db, key, opts \\ [])

Removes a key from the database.

Parameters

  • db - The database server (PID or registered name)
  • key - The key to remove
  • opts - A keyword list with the following options (default: []):
    • :tag - Tag the key is namespaced under
    • :timeout - Timeout (in milliseconds) for the calls (default: 5000)

Returns

  • :ok

Examples

Goblin.remove(db, :alice)
# => :ok

Goblin.get(db, :alice)
# => nil

remove_multi(db, keys, opts \\ [])

Removes multiple keys from the database in a single transaction.

Parameters

  • db - The database server (PID or registered name)
  • keys - A list of keys to remove
  • opts - A keyword list with the following options (default: []):
    • :tag - Tag the keys are namespaced under
    • :timeout - Timeout (in milliseconds) for the calls (default: 5000)

Returns

  • :ok

Examples

Goblin.remove_multi(db, [:alice, :bob, :charlie])
# => :ok

scan(db, opts \\ [])

Returns a stream of key-value pairs, optionally bounded by a range. Captures snapshots at enumeration.

Entries are sorted by key in ascending order. Both min and max are inclusive.

Parameters

  • db - The database server (PID or registered name)
  • opts - Keyword list of options:
    • :min - Minimum key, inclusive (optional)
    • :max - Maximum key, inclusive (optional)
    • :tag - Tag to filter by (optional)

Returns

  • A stream of {key, value} tuples

Examples

Goblin.scan(db) |> Enum.to_list()
# => [{:alice, "Alice"}, {:bob, "Bob"}, {:charlie, "Charlie"}]

Goblin.scan(db, min: :bob) |> Enum.to_list()
# => [{:bob, "Bob"}, {:charlie, "Charlie"}]

Goblin.scan(db, min: :alice, max: :bob) |> Enum.to_list()
# => [{:alice, "Alice"}, {:bob, "Bob"}]

scan = Goblin.scan(db)
Enum.to_list(scan)
# => []
Goblin.put(db, :alice, "Alice")
Enum.to_list(scan)
# => [{:alice, "Alice"}]

start(opts)

Starts the database, see start_link/1 for more details.

start_link(opts)

Starts the database.

Creates the data_dir if it does not exist.

Options

  • :name - Registered name for the database (optional, defaults to Goblin)
  • :data_dir - Directory path for database files (required)
  • :mem_limit - Bytes to buffer in memory before flushing to disk (default: 64 MB)
  • :bf_fpp - Bloom filter false positive probability (default: 0.01)

Returns

  • {:ok, pid} - On successful start
  • {:error, reason} - On failure

Examples

{:ok, db} = Goblin.start_link(
  name: MyApp.DB,
  data_dir: "/var/lib/myapp/db"
)

stop(db, reason \\ :normal, timeout \\ :infinity)

@spec stop(:gen_statem.server_ref(), term(), timeout()) :: :ok

Stops the database.

sweeping(atom1, atom2, db)

transaction(db, callback, opts \\ [])

Executes a read-write transaction.

Transactions are executed serially and are ACID-compliant. The provided function receives a transaction struct and must return {:commit, tx, reply} to commit, or {:abort, reply} to abort.

Parameters

  • db - The database server (PID or registered name)
  • callback - A function that takes a Goblin.Tx.t() and returns a transaction result
  • opts - A keyword list with options:
    • :timeout - Timeout (in milliseconds) for the calls (default: 5000)

Returns

  • reply - The reply from {:commit, tx, reply} when committed
  • {:error, :aborted} - When the transaction is aborted

Examples

Goblin.transaction(db, fn tx ->
  counter = Goblin.Tx.get(tx, :counter, default: 0)
  tx
  |> Goblin.Tx.put(:counter, counter + 1)
  |> Goblin.Tx.commit()
end)
# => :ok

Goblin.transaction(db, fn tx ->
  tx
  |> Goblin.Tx.abort()
end)
# => :error