aboutsummaryrefslogtreecommitdiff
path: root/shard/lib/data/store.ex
blob: ca12cd03967f87af66dd13e561fa826979f6f716 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
defprotocol SData.Page do
  @moduledoc"""
  Protocol to be implemented by objects that are used as data pages
  in a pagestore and that may reference other data pages by their hash.
  """

  @fallback_to_any true

  @doc"""
  Get hashes of all pages referenced by this page.
  """
  def refs(page)
end

defimpl SData.Page, for: Any do
  def refs(_page), do: []
end


defprotocol SData.PageStore do
  @moduledoc"""
  Protocol to be implemented for page stores to allow their
  manipulation.

  This protocol may also be implemented by store proxies that track
  operations and implement different synchronization or caching mechanisms.
  """

  @doc"""
  Put a page. Argument is the content of the page, returns the
  hash that the store has associated to it.

  Returns {hash, store}
  """
  def put(store, page)

  @doc"""
  Get a page referenced by its hash.

  Returns page
  """
  def get(store, hash)

  @doc"""
  Copy to the store a page and all its references from the other store.
  In the case of pages on the network in a distributed store, this may
  be lazy.

  Returns store
  """
  def copy(store, other_store, hash)

  @doc"""
  Free a page referenced by its hash, marking it as no longer needed.

  Returns store
  """
  def free(store, hash)
end


defmodule SData.LocalStore do
  defstruct [:pages] 

  def new() do
    %SData.LocalStore{ pages: %{} }
  end
end

defimpl SData.PageStore, for: SData.LocalStore do
  def put(store, page) do
    hash = SData.term_hash page
    store = %{ store | pages: Map.put(store.pages, hash, page) }
    { hash, store }
  end

  def get(store, hash) do
    store.pages[hash]
  end

  def copy(store, other_store, hash) do
    page = SData.PageStore.get(other_store, hash)
    refs = SData.Page.refs(page)
    store = Enum.reduce(refs, store, fn x, acc -> copy(acc, other_store, x) end)
    %{ store | pages: Map.put(store.pages, hash, page) }
  end

  def free(store, hash) do
    %{ store | pages: Map.delete(store.pages, hash) }
  end
end