Skip to content

Commit

Permalink
Create snapshot functionality
Browse files Browse the repository at this point in the history
With this, we have a very slow way of effectively slowly snapshotting
the database.

Very slow, someone should do a better method than what I'm doing here
  • Loading branch information
mariari committed Dec 31, 2023
1 parent e6a91ea commit 0e5ca7d
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
49 changes: 49 additions & 0 deletions lib/anoma/storage.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,16 @@ defmodule Anoma.Storage do
Please see my testing module `AnomaTest.Storage` to learn more on
how to use me
### Snapshots
One can snapshot the keys provided in the code by running the following
- `snapshot_order/1`
- `put_snapshot/2`
- `in_snapshot/2`
- `get_at_snapshot/2`
"""

use TypedStruct

@typedoc """
Expand Down Expand Up @@ -64,6 +73,8 @@ defmodule Anoma.Storage do
@type qualified_key() :: nonempty_improper_list(any(), non_neg_integer())
@type qualified_value() :: any()

@type snapshot() :: {t(), list({order_key(), non_neg_integer()})}

############################################################
# Creation API #
############################################################
Expand Down Expand Up @@ -169,6 +180,44 @@ defmodule Anoma.Storage do
end
end

############################################################
# Snapshots #
############################################################

@spec snapshot_order(t()) :: result(snapshot())
def snapshot_order(storage) do
:mnesia.transaction(fn ->
snapshot = [{{:"$1", :"$2", :"$3"}, [], [{{:"$2", :"$3"}}]}]
{storage, :mnesia.select(storage.order, snapshot)}
end)
end

@spec put_snapshot(t(), order_key()) :: result(:ok)
def put_snapshot(storage, key) do
with {:atomic, snapshot} <- snapshot_order(storage) do
put(storage, key, snapshot)
end
end

@spec in_snapshot(snapshot(), order_key()) :: nil | non_neg_integer()
def in_snapshot({_, snapshot}, key) do
List.keyfind(snapshot, key, 0, {nil, nil})
|> elem(1)
end

@spec get_at_snapshot(snapshot(), order_key()) ::
:absent | {:ok, qualified_value()}
def get_at_snapshot(snapshot = {storage, _}, key) do
position = in_snapshot(snapshot, key)

with {:atomic, [{_, [^position, ^key | 0], value}]} <-
read_at_order(storage, key, position) do
{:ok, value}
else
_ -> :absent
end
end

############################################################
# Queries #
############################################################
Expand Down
27 changes: 27 additions & 0 deletions test/storage_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,31 @@ defmodule AnomaTest.Storage do
{:atomic, [{storage.order, testing_atom, 3}]}
end
end

describe "Snapshots" do
test "snapshots properly put", %{storage: storage} do
snapshot_storage = :snapshot_super_secret
assert {:atomic, :ok} = Storage.put_snapshot(storage, snapshot_storage)
assert {:ok, _} = Storage.get(storage, snapshot_storage)
end

test "snapshots properly get the latest", %{storage: storage} do
snapshot_storage = :super_hot
testing_atom = 111_222_333_444_555_666
Storage.write_at_order(storage, testing_atom, 10, 3)
assert {:atomic, :ok} = Storage.put_snapshot(storage, snapshot_storage)
assert {:ok, snapshot} = Storage.get(storage, snapshot_storage)
assert Storage.in_snapshot(snapshot, testing_atom) == 3

assert Storage.get_at_snapshot(snapshot, testing_atom) ==
{:ok, 10}
end

test "missing key gives us nil", %{storage: storage} do
snapshot_storage = :super_hot_hot
nonsense_atom = :very_good_atom
assert {:atomic, snapshot} = Storage.snapshot_order(storage)
assert Storage.get_at_snapshot(snapshot, nonsense_atom)
end
end
end

0 comments on commit 0e5ca7d

Please sign in to comment.