Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 144 lines (118 sloc) 3.907 kB
a4e794d @joearms starting
authored
1 %% Copyright (c) 2006-2009 Joe Armstrong
2 %% See MIT-LICENSE for licensing information.
3
4 -module(elib1_guid_store).
5
6 %% The entire history of a file is kept in an association list
7 %% as a set of patches
8
9 -export([test/0, store/1, fetch/1, fetch/2]).
10 -import(lists, [reverse/1, reverse/2, filter/2, member/2]).
11
12 test() ->
13 file:delete("myblob.dets"),
14 elib1_blob_store:open("myblob.dets"),
15 store([{guid,g1},{name,joe},{content,"abc"}]),
16 store([{guid,g1},{name,joe1},{content,"abc\ndef"}]),
17 store([{guid,g1},{date,123},{content,"123"}]),
18 store([{guid,g1},{date,125},{stuff,123}, {content,"123abc\ndef\n\234"}]),
19 store([{guid,g1},{nonsense,foodedo}, {content,""}]),
20 store([{guid,g1},{nonsense,foodedo12313}, {content,"123123"}]),
21 elib1_blob_store:close().
22
23 fetch(Guid) -> fetch(Guid, 0).
24
25 fetch(Guid, N) ->
26 case elib1_blob_store:fetch(Guid) of
27 {ok, OldBlob} ->
28 {Meta, Patches} = binary_to_term(OldBlob),
29 fetch1(Meta, N, Patches);
30 error ->
31 exit(eBadGuid)
32 end.
33
34 fetch1(Meta, 0, _) -> Meta;
35 fetch1(Meta, N, [P|T]) ->
36 OldMeta = patch(P, Meta),
37 fetch1(OldMeta, N-1, T);
38 fetch1(_, N, []) ->
39 exit({ebadLevel,N}).
40
41 store(Assoc) ->
42 Guid = must(guid, Assoc),
43 NewBlob = case elib1_blob_store:fetch(Guid) of
44 {ok, OldBlob} ->
45 {OldMeta, Patches} = binary_to_term(OldBlob),
46 P = diff(Assoc, OldMeta),
47 term_to_binary({Assoc,[P|Patches]});
48 error ->
49 P = diff(Assoc, [{content,""}]),
50 term_to_binary({Assoc,[P]})
51
52 end,
53 elib1_blob_store:store(Guid, NewBlob).
54
55 %% patch(P, NewMeta) -> OldMeta'
56
57 patch([{k,K,V}|T], Meta) ->
58 %% key replace
59 Meta1 = replace(K, V, Meta, []),
60 patch(T, Meta1);
61 patch([{d,K}|T], Meta) ->
62 Meta1 = delete_key(K, Meta),
63 patch(T, Meta1);
64 patch([{p,P}|T], Meta) ->
65 NewContent = must(content, Meta),
66 OldContent = elib1_diff:patch(NewContent, P),
67 Meta1 = replace(content, OldContent, Meta, []),
68 patch(T, Meta1);
69 patch([], Meta) ->
70 lists:sort(Meta).
71
72 %% diff(NewMeta, OldMeta) -> Patches
73 %% compute the diffs necessary to turn the current metadata and content
74 %% into the old metadata and content
75
76 diff(NewMeta, OldMeta) ->
77 Patch = diff1(NewMeta, OldMeta),
78 %% io:format("Patches=~p~n",[Patch]),
79 Old = patch(Patch, NewMeta),
80 case {lists:sort(Old),
81 lists:sort(OldMeta)} of
82 {A, A} ->
83 io:format("patches ok ...~n"),
84 Patch;
85 _ ->
86 io:format("oops debug me"),
87 elib1_misc:dump("debug",{newMeta,lists:sort(NewMeta),
88 oldMeta,lists:sort(OldMeta),
89 patch, Patch,
90 old, lists:sort(Old)}),
91 exit(oops)
92 end.
93
94 %% comput a patch to turn New into Old
95
96 diff1(NewMeta, OldMeta) ->
97 L1 = deletions(NewMeta, OldMeta),
98 diff(OldMeta, NewMeta, L1).
99
100 deletions(New, Old) ->
101 %% keys in new that are just not in Old
102 NewKeys = [K || {K,_} <- New],
103 OldKeys = [K || {K,_} <- Old],
104 L = filter(fun(I) -> not member(I, OldKeys) end, NewKeys),
105 [{d,I} || I <- L].
106
107 diff([{content,OldContent}|T], New, L) ->
108 NewContent = must(content, New),
109 P = elib1_diff:diff(OldContent, NewContent),
110 diff(T, New, [{p,P}|L]);
111 diff([{K,V}|T], New, L) ->
112 case lookup(K, New) of
113 {value, V} ->
114 %% same value in both no change
115 diff(T, New, L);
116 _ ->
117 %% not the same value or missing
118 diff(T, New, [{k,K,V}|L])
119 end;
120 diff([], _, L) ->
121 L.
122
123 lookup(Key, L) ->
124 case lists:keysearch(Key, 1, L) of
125 {value, {_,V}} -> {value, V};
126 false -> false
127 end.
128
129
130 must(K, [{K,V}|_]) -> V;
131 must(K, [_|T]) -> must(K, T);
132 must(K, []) -> exit({eMissingkey, K}).
133
134 replace(K, V, [{K,_}|T], L) -> reverse(L, [{K,V}|T]);
135 replace(K, V, [H|T], L) -> replace(K, V, T, [H|L]);
136 replace(K, V, [], L) -> [{K,V}|L].
137
138 delete_key(K, [{K,_}|T]) -> T;
139 delete_key(K, [H|T]) -> [H|delete_key(K, T)];
140 delete_key(_, []) -> [].
141
142
143
Something went wrong with that request. Please try again.