Skip to content

Instantly share code, notes, and snippets.

@hansonkd
Created January 18, 2022 17:41
Show Gist options
  • Save hansonkd/a0a974704a8483216dca2a1e79c00e62 to your computer and use it in GitHub Desktop.
Save hansonkd/a0a974704a8483216dca2a1e79c00e62 to your computer and use it in GitHub Desktop.
defmodule CubDB.Store.MerkleStore do
@moduledoc false
# `CubDB.Store.MerkleStore` is an implementation of the `Store` protocol
# intended for test purposes only. It is backed by a map, but supports all the
# operations of a `CubDB.Store`. It allows some tests to be simpler and faster
# by avoid using the file system.
defstruct agent: nil
alias CubDB.Store.MerkleStore
@type t :: %MerkleStore{agent: pid}
@spec create() :: {:ok, t} | {:error, term}
def create do
with {:ok, pid} <- Agent.start_link(fn -> {%{}, nil} end) do
{:ok, %MerkleStore{agent: pid}}
end
end
end
defimpl CubDB.Store, for: CubDB.Store.MerkleStore do
alias CubDB.Store.MerkleStore
def clean_up(_store, cpid, btree) do
:ok
end
def clean_up_old_compaction_files(store, pid) do
:ok
end
def start_cleanup(%MerkleStore{}) do
{:ok, nil}
end
def next_compaction_store(%MerkleStore{}) do
Store.MerkleStore.create()
end
def put_node(%MerkleStore{agent: agent}, node) do
Agent.get_and_update(
agent,
fn {map, latest_header_loc} ->
loc = :crypto.hash(:blake2b, :erlang.term_to_binary(node))
{loc, {Map.put(map, loc, node), latest_header_loc}}
end,
:infinity
)
end
def put_header(%MerkleStore{agent: agent}, header) do
Agent.get_and_update(
agent,
fn {map, _} ->
loc = :crypto.hash(:blake2b, :erlang.term_to_binary(header))
{loc, {Map.put(map, loc, header), loc}}
end,
:infinity
)
end
def sync(%MerkleStore{}), do: :ok
def get_node(%MerkleStore{agent: agent}, location) do
case Agent.get(
agent,
fn {map, _} ->
Map.fetch(map, location)
end,
:infinity
) do
{:ok, value} -> value
:error -> raise(ArgumentError, message: "End of file")
end
end
def get_latest_header(%MerkleStore{agent: agent}) do
Agent.get(
agent,
fn
{_, nil} -> nil
{map, header_loc} -> {header_loc, Map.get(map, header_loc)}
end,
:infinity
)
end
def close(%MerkleStore{agent: agent}) do
Agent.stop(agent, :normal, :infinity)
end
def blank?(%MerkleStore{agent: agent}) do
Agent.get(
agent,
fn
{_, nil} -> true
_ -> false
end,
:infinity
)
end
def open?(%MerkleStore{agent: agent}) do
Process.alive?(agent)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment