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
92
93
94
95
96
97
98
99
100
101
102
|
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.
A page store is an object that stores data pages (arbitrary Erlang terms) and
identifies them by their hash. Dependencies may exist between pages, in which
case they form a Merkle DAG.
"""
@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
@moduledoc"""
A page store that saves all pages locally in RAM. The store is basically a dictionnary
of hash to term mappings, which is mutated by put operations.
"""
defstruct [:pages]
@doc"""
Create empty LocalStore.
"""
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
|