34
35:- module(gitty_driver_bdb,
36 [ gitty_close/1, 37 gitty_file/3, 38
39 gitty_update_head/4, 40 delete_head/2, 41 set_head/3, 42 store_object/4, 43 delete_object/2, 44
45 gitty_hash/2, 46 load_plain_commit/3, 47 load_object/5 48 ]). 49:- use_module(library(zlib)). 50:- use_module(library(dcg/basics)). 51:- use_module(library(memfile)). 52:- use_module(library(bdb)). 53
65
66
67:- dynamic
68 bdb_env/2, 69 bdb_db/3. 70:- volatile
71 bdb_env/2,
72 bdb_db/3. 73
74
75bdb_handle(Store, Database, Handle) :-
76 bdb_db(Store, Database, Handle), !.
77bdb_handle(Store, Database, Handle) :-
78 with_mutex(gitty_bdb, bdb_handle_sync(Store, Database, Handle)).
79
80bdb_handle_sync(Store, Database, Handle) :-
81 bdb_db(Store, Database, Handle), !.
82bdb_handle_sync(Store, Database, Handle) :-
83 bdb_store(Store, Env),
84 db_types(Database, KeyType, ValueType),
85 bdb_open(Database, update, Handle,
86 [ environment(Env),
87 key(KeyType),
88 value(ValueType)
89 ]),
90 asserta(bdb_db(Store, Database, Handle)).
91
92db_types(heads, atom, atom). 93db_types(objects, atom, c_blob). 94
98
99bdb_store(Store, Env) :-
100 bdb_env(Store, Env), !.
101bdb_store(Store, Env) :-
102 with_mutex(gitty_bdb, bdb_store_sync(Store, Env)).
103
104bdb_store_sync(Store, Env) :-
105 bdb_env(Store, Env), !.
106bdb_store_sync(Store, Env) :-
107 ensure_directory(Store),
108 bdb_init(Env,
109 [ home(Store),
110 create(true),
111 thread(true),
112 init_txn(true),
113 recover(true),
114 register(true)
115 ]),
116 asserta(bdb_env(Store, Env)).
117
118ensure_directory(Dir) :-
119 exists_directory(Dir), !.
120ensure_directory(Dir) :-
121 make_directory(Dir).
122
126
127gitty_close(Store) :-
128 with_mutex(gitty_bdb, gitty_close_sync(Store)).
129
130gitty_close_sync(Store) :-
131 ( retract(bdb_env(Store, Env))
132 -> bdb_close_environment(Env)
133 ; true
134 ).
135
136
141
142gitty_file(Store, Head, Hash) :-
143 bdb_handle(Store, heads, H),
144 ( nonvar(Head)
145 -> bdb_get(H, Head, Hash)
146 ; bdb_enum(H, Head, Hash)
147 ).
148
161
162gitty_update_head(Store, Name, OldCommit, NewCommit) :-
163 bdb_store(Store, Env),
164 bdb_transaction(
165 Env,
166 gitty_update_head_sync(Store, Name, OldCommit, NewCommit)).
167
168gitty_update_head_sync(Store, Name, OldCommit, NewCommit) :-
169 bdb_handle(Store, heads, BDB),
170 ( OldCommit == (-)
171 -> ( bdb_get(BDB, Name, _)
172 -> throw(error(gitty(file_exists(Name),_)))
173 ; bdb_put(BDB, Name, NewCommit)
174 )
175 ; ( bdb_get(BDB, Name, OldCommit)
176 -> bdb_put(BDB, Name, NewCommit)
177 ; throw(error(gitty(not_at_head(Name, OldCommit)), _))
178 )
179 ).
180
184
185delete_head(Store, Name) :-
186 bdb_handle(Store, heads, BDB),
187 bdb_del(BDB, Name, _Old).
188
192
193set_head(Store, File, Hash) :-
194 bdb_handle(Store, heads, BDB),
195 bdb_put(BDB, File, Hash).
196
201
202load_plain_commit(Store, Hash, Meta) :-
203 load_object(Store, Hash, String, commit, _Size),
204 term_string(Meta, String, []).
205
210
211store_object(Store, Hash, Hdr, Data) :-
212 compress_string(Hdr, Data, Object),
213 bdb_handle(Store, objects, BDB),
214 bdb_put(BDB, Hash, Object).
215
216compress_string(Header, Data, String) :-
217 setup_call_cleanup(
218 new_memory_file(MF),
219 ( setup_call_cleanup(
220 open_memory_file(MF, write, Out, [encoding(utf8)]),
221 setup_call_cleanup(
222 zopen(Out, OutZ, [ format(gzip),
223 close_parent(false)
224 ]),
225 format(OutZ, '~s~s', [Header, Data]),
226 close(OutZ)),
227 close(Out)),
228 memory_file_to_string(MF, String, octet)
229 ),
230 free_memory_file(MF)).
231
237
238load_object(Store, Hash, Data, Type, Size) :-
239 bdb_handle(Store, objects, BDB),
240 bdb_get(BDB, Hash, Blob),
241 setup_call_cleanup(
242 open_string(Blob, In),
243 setup_call_cleanup(
244 zopen(In, InZ, [ format(gzip),
245 close_parent(false)
246 ]),
247 ( set_stream(InZ, encoding(utf8)),
248 read_object(InZ, Data, Type, Size)
249 ),
250 close(InZ)),
251 close(In)).
252
253read_object(In, Data, Type, Size) :-
254 get_code(In, C0),
255 read_hdr(C0, In, Hdr),
256 phrase((nonblanks(TypeChars), " ", integer(Size)), Hdr),
257 atom_codes(Type, TypeChars),
258 read_string(In, _, Data).
259
260read_hdr(C, In, [C|T]) :-
261 C > 0, !,
262 get_code(In, C1),
263 read_hdr(C1, In, T).
264read_hdr(_, _, []).
265
269
270gitty_hash(Store, Hash) :-
271 bdb_handle(Store, objects, BDB),
272 ( nonvar(Hash)
273 -> bdb_get(BDB, Hash, _)
274 ; bdb_enum(BDB, Hash, _)
275 ).
276
280
281delete_object(Store, Hash) :-
282 bdb_handle(Store, objects, BDB),
283 bdb_del(BDB, Hash, _)