Line | Count | Source (jump to first uncovered line) |
1 | | #include "git-compat-util.h" |
2 | | #include "hex.h" |
3 | | #include "refs-internal.h" |
4 | | #include "string-list.h" |
5 | | #include "trace.h" |
6 | | |
7 | | static struct trace_key trace_refs = TRACE_KEY_INIT(REFS); |
8 | | |
9 | | struct debug_ref_store { |
10 | | struct ref_store base; |
11 | | struct ref_store *refs; |
12 | | }; |
13 | | |
14 | | extern struct ref_storage_be refs_be_debug; |
15 | | |
16 | | struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_store *store) |
17 | 0 | { |
18 | 0 | struct debug_ref_store *res; |
19 | 0 | struct ref_storage_be *be_copy; |
20 | |
|
21 | 0 | if (!trace_want(&trace_refs)) { |
22 | 0 | return store; |
23 | 0 | } |
24 | 0 | res = xmalloc(sizeof(struct debug_ref_store)); |
25 | 0 | be_copy = xmalloc(sizeof(*be_copy)); |
26 | 0 | *be_copy = refs_be_debug; |
27 | | /* we never deallocate backends, so safe to copy the pointer. */ |
28 | 0 | be_copy->name = store->be->name; |
29 | 0 | trace_printf_key(&trace_refs, "ref_store for %s\n", gitdir); |
30 | 0 | res->refs = store; |
31 | 0 | base_ref_store_init((struct ref_store *)res, store->repo, gitdir, |
32 | 0 | be_copy); |
33 | 0 | return (struct ref_store *)res; |
34 | 0 | } |
35 | | |
36 | | static void debug_release(struct ref_store *refs) |
37 | 0 | { |
38 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)refs; |
39 | 0 | drefs->refs->be->release(drefs->refs); |
40 | 0 | trace_printf_key(&trace_refs, "release\n"); |
41 | 0 | } |
42 | | |
43 | | static int debug_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err) |
44 | 0 | { |
45 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)refs; |
46 | 0 | int res = drefs->refs->be->create_on_disk(drefs->refs, flags, err); |
47 | 0 | trace_printf_key(&trace_refs, "create_on_disk: %d\n", res); |
48 | 0 | return res; |
49 | 0 | } |
50 | | |
51 | | static int debug_transaction_prepare(struct ref_store *refs, |
52 | | struct ref_transaction *transaction, |
53 | | struct strbuf *err) |
54 | 0 | { |
55 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)refs; |
56 | 0 | int res; |
57 | 0 | transaction->ref_store = drefs->refs; |
58 | 0 | res = drefs->refs->be->transaction_prepare(drefs->refs, transaction, |
59 | 0 | err); |
60 | 0 | trace_printf_key(&trace_refs, "transaction_prepare: %d \"%s\"\n", res, |
61 | 0 | err->buf); |
62 | 0 | return res; |
63 | 0 | } |
64 | | |
65 | | static void print_update(int i, const char *refname, |
66 | | const struct object_id *old_oid, |
67 | | const struct object_id *new_oid, unsigned int flags, |
68 | | unsigned int type, const char *msg) |
69 | 0 | { |
70 | 0 | char o[GIT_MAX_HEXSZ + 1] = "null"; |
71 | 0 | char n[GIT_MAX_HEXSZ + 1] = "null"; |
72 | 0 | if (old_oid) |
73 | 0 | oid_to_hex_r(o, old_oid); |
74 | 0 | if (new_oid) |
75 | 0 | oid_to_hex_r(n, new_oid); |
76 | |
|
77 | 0 | type &= 0xf; /* see refs.h REF_* */ |
78 | 0 | flags &= REF_HAVE_NEW | REF_HAVE_OLD | REF_NO_DEREF | |
79 | 0 | REF_FORCE_CREATE_REFLOG; |
80 | 0 | trace_printf_key(&trace_refs, "%d: %s %s -> %s (F=0x%x, T=0x%x) \"%s\"\n", i, refname, |
81 | 0 | o, n, flags, type, msg); |
82 | 0 | } |
83 | | |
84 | | static void print_transaction(struct ref_transaction *transaction) |
85 | 0 | { |
86 | 0 | int i; |
87 | 0 | trace_printf_key(&trace_refs, "transaction {\n"); |
88 | 0 | for (i = 0; i < transaction->nr; i++) { |
89 | 0 | struct ref_update *u = transaction->updates[i]; |
90 | 0 | print_update(i, u->refname, &u->old_oid, &u->new_oid, u->flags, |
91 | 0 | u->type, u->msg); |
92 | 0 | } |
93 | 0 | trace_printf_key(&trace_refs, "}\n"); |
94 | 0 | } |
95 | | |
96 | | static int debug_transaction_finish(struct ref_store *refs, |
97 | | struct ref_transaction *transaction, |
98 | | struct strbuf *err) |
99 | 0 | { |
100 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)refs; |
101 | 0 | int res; |
102 | 0 | transaction->ref_store = drefs->refs; |
103 | 0 | res = drefs->refs->be->transaction_finish(drefs->refs, transaction, |
104 | 0 | err); |
105 | 0 | print_transaction(transaction); |
106 | 0 | trace_printf_key(&trace_refs, "finish: %d\n", res); |
107 | 0 | return res; |
108 | 0 | } |
109 | | |
110 | | static int debug_transaction_abort(struct ref_store *refs, |
111 | | struct ref_transaction *transaction, |
112 | | struct strbuf *err) |
113 | 0 | { |
114 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)refs; |
115 | 0 | int res; |
116 | 0 | transaction->ref_store = drefs->refs; |
117 | 0 | res = drefs->refs->be->transaction_abort(drefs->refs, transaction, err); |
118 | 0 | return res; |
119 | 0 | } |
120 | | |
121 | | static int debug_initial_transaction_commit(struct ref_store *refs, |
122 | | struct ref_transaction *transaction, |
123 | | struct strbuf *err) |
124 | 0 | { |
125 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)refs; |
126 | 0 | int res; |
127 | 0 | transaction->ref_store = drefs->refs; |
128 | 0 | res = drefs->refs->be->initial_transaction_commit(drefs->refs, |
129 | 0 | transaction, err); |
130 | 0 | return res; |
131 | 0 | } |
132 | | |
133 | | static int debug_pack_refs(struct ref_store *ref_store, struct pack_refs_opts *opts) |
134 | 0 | { |
135 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
136 | 0 | int res = drefs->refs->be->pack_refs(drefs->refs, opts); |
137 | 0 | trace_printf_key(&trace_refs, "pack_refs: %d\n", res); |
138 | 0 | return res; |
139 | 0 | } |
140 | | |
141 | | static int debug_rename_ref(struct ref_store *ref_store, const char *oldref, |
142 | | const char *newref, const char *logmsg) |
143 | 0 | { |
144 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
145 | 0 | int res = drefs->refs->be->rename_ref(drefs->refs, oldref, newref, |
146 | 0 | logmsg); |
147 | 0 | trace_printf_key(&trace_refs, "rename_ref: %s -> %s \"%s\": %d\n", oldref, newref, |
148 | 0 | logmsg, res); |
149 | 0 | return res; |
150 | 0 | } |
151 | | |
152 | | static int debug_copy_ref(struct ref_store *ref_store, const char *oldref, |
153 | | const char *newref, const char *logmsg) |
154 | 0 | { |
155 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
156 | 0 | int res = |
157 | 0 | drefs->refs->be->copy_ref(drefs->refs, oldref, newref, logmsg); |
158 | 0 | trace_printf_key(&trace_refs, "copy_ref: %s -> %s \"%s\": %d\n", oldref, newref, |
159 | 0 | logmsg, res); |
160 | 0 | return res; |
161 | 0 | } |
162 | | |
163 | | struct debug_ref_iterator { |
164 | | struct ref_iterator base; |
165 | | struct ref_iterator *iter; |
166 | | }; |
167 | | |
168 | | static int debug_ref_iterator_advance(struct ref_iterator *ref_iterator) |
169 | 0 | { |
170 | 0 | struct debug_ref_iterator *diter = |
171 | 0 | (struct debug_ref_iterator *)ref_iterator; |
172 | 0 | int res = diter->iter->vtable->advance(diter->iter); |
173 | 0 | if (res) |
174 | 0 | trace_printf_key(&trace_refs, "iterator_advance: (%d)\n", res); |
175 | 0 | else |
176 | 0 | trace_printf_key(&trace_refs, "iterator_advance: %s (0)\n", |
177 | 0 | diter->iter->refname); |
178 | |
|
179 | 0 | diter->base.refname = diter->iter->refname; |
180 | 0 | diter->base.oid = diter->iter->oid; |
181 | 0 | diter->base.flags = diter->iter->flags; |
182 | 0 | return res; |
183 | 0 | } |
184 | | |
185 | | static int debug_ref_iterator_peel(struct ref_iterator *ref_iterator, |
186 | | struct object_id *peeled) |
187 | 0 | { |
188 | 0 | struct debug_ref_iterator *diter = |
189 | 0 | (struct debug_ref_iterator *)ref_iterator; |
190 | 0 | int res = diter->iter->vtable->peel(diter->iter, peeled); |
191 | 0 | trace_printf_key(&trace_refs, "iterator_peel: %s: %d\n", diter->iter->refname, res); |
192 | 0 | return res; |
193 | 0 | } |
194 | | |
195 | | static int debug_ref_iterator_abort(struct ref_iterator *ref_iterator) |
196 | 0 | { |
197 | 0 | struct debug_ref_iterator *diter = |
198 | 0 | (struct debug_ref_iterator *)ref_iterator; |
199 | 0 | int res = diter->iter->vtable->abort(diter->iter); |
200 | 0 | trace_printf_key(&trace_refs, "iterator_abort: %d\n", res); |
201 | 0 | return res; |
202 | 0 | } |
203 | | |
204 | | static struct ref_iterator_vtable debug_ref_iterator_vtable = { |
205 | | .advance = debug_ref_iterator_advance, |
206 | | .peel = debug_ref_iterator_peel, |
207 | | .abort = debug_ref_iterator_abort, |
208 | | }; |
209 | | |
210 | | static struct ref_iterator * |
211 | | debug_ref_iterator_begin(struct ref_store *ref_store, const char *prefix, |
212 | | const char **exclude_patterns, unsigned int flags) |
213 | 0 | { |
214 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
215 | 0 | struct ref_iterator *res = |
216 | 0 | drefs->refs->be->iterator_begin(drefs->refs, prefix, |
217 | 0 | exclude_patterns, flags); |
218 | 0 | struct debug_ref_iterator *diter = xcalloc(1, sizeof(*diter)); |
219 | 0 | base_ref_iterator_init(&diter->base, &debug_ref_iterator_vtable); |
220 | 0 | diter->iter = res; |
221 | 0 | trace_printf_key(&trace_refs, "ref_iterator_begin: \"%s\" (0x%x)\n", |
222 | 0 | prefix, flags); |
223 | 0 | return &diter->base; |
224 | 0 | } |
225 | | |
226 | | static int debug_read_raw_ref(struct ref_store *ref_store, const char *refname, |
227 | | struct object_id *oid, struct strbuf *referent, |
228 | | unsigned int *type, int *failure_errno) |
229 | 0 | { |
230 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
231 | 0 | int res = 0; |
232 | |
|
233 | 0 | oidcpy(oid, null_oid()); |
234 | 0 | res = drefs->refs->be->read_raw_ref(drefs->refs, refname, oid, referent, |
235 | 0 | type, failure_errno); |
236 | |
|
237 | 0 | if (res == 0) { |
238 | 0 | trace_printf_key(&trace_refs, "read_raw_ref: %s: %s (=> %s) type %x: %d\n", |
239 | 0 | refname, oid_to_hex(oid), referent->buf, *type, res); |
240 | 0 | } else { |
241 | 0 | trace_printf_key(&trace_refs, |
242 | 0 | "read_raw_ref: %s: %d (errno %d)\n", refname, |
243 | 0 | res, *failure_errno); |
244 | 0 | } |
245 | 0 | return res; |
246 | 0 | } |
247 | | |
248 | | static int debug_read_symbolic_ref(struct ref_store *ref_store, const char *refname, |
249 | | struct strbuf *referent) |
250 | 0 | { |
251 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
252 | 0 | struct ref_store *refs = drefs->refs; |
253 | 0 | int res; |
254 | |
|
255 | 0 | res = refs->be->read_symbolic_ref(refs, refname, referent); |
256 | 0 | if (!res) |
257 | 0 | trace_printf_key(&trace_refs, "read_symbolic_ref: %s: (%s)\n", |
258 | 0 | refname, referent->buf); |
259 | 0 | else |
260 | 0 | trace_printf_key(&trace_refs, |
261 | 0 | "read_symbolic_ref: %s: %d\n", refname, res); |
262 | 0 | return res; |
263 | |
|
264 | 0 | } |
265 | | |
266 | | static struct ref_iterator * |
267 | | debug_reflog_iterator_begin(struct ref_store *ref_store) |
268 | 0 | { |
269 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
270 | 0 | struct ref_iterator *res = |
271 | 0 | drefs->refs->be->reflog_iterator_begin(drefs->refs); |
272 | 0 | trace_printf_key(&trace_refs, "for_each_reflog_iterator_begin\n"); |
273 | 0 | return res; |
274 | 0 | } |
275 | | |
276 | | struct debug_reflog { |
277 | | const char *refname; |
278 | | each_reflog_ent_fn *fn; |
279 | | void *cb_data; |
280 | | }; |
281 | | |
282 | | static int debug_print_reflog_ent(struct object_id *old_oid, |
283 | | struct object_id *new_oid, |
284 | | const char *committer, timestamp_t timestamp, |
285 | | int tz, const char *msg, void *cb_data) |
286 | 0 | { |
287 | 0 | struct debug_reflog *dbg = (struct debug_reflog *)cb_data; |
288 | 0 | int ret; |
289 | 0 | char o[GIT_MAX_HEXSZ + 1] = "null"; |
290 | 0 | char n[GIT_MAX_HEXSZ + 1] = "null"; |
291 | 0 | char *msgend = strchrnul(msg, '\n'); |
292 | 0 | if (old_oid) |
293 | 0 | oid_to_hex_r(o, old_oid); |
294 | 0 | if (new_oid) |
295 | 0 | oid_to_hex_r(n, new_oid); |
296 | |
|
297 | 0 | ret = dbg->fn(old_oid, new_oid, committer, timestamp, tz, msg, |
298 | 0 | dbg->cb_data); |
299 | 0 | trace_printf_key(&trace_refs, |
300 | 0 | "reflog_ent %s (ret %d): %s -> %s, %s %ld \"%.*s\"\n", |
301 | 0 | dbg->refname, ret, o, n, committer, |
302 | 0 | (long int)timestamp, (int)(msgend - msg), msg); |
303 | 0 | return ret; |
304 | 0 | } |
305 | | |
306 | | static int debug_for_each_reflog_ent(struct ref_store *ref_store, |
307 | | const char *refname, each_reflog_ent_fn fn, |
308 | | void *cb_data) |
309 | 0 | { |
310 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
311 | 0 | struct debug_reflog dbg = { |
312 | 0 | .refname = refname, |
313 | 0 | .fn = fn, |
314 | 0 | .cb_data = cb_data, |
315 | 0 | }; |
316 | |
|
317 | 0 | int res = drefs->refs->be->for_each_reflog_ent( |
318 | 0 | drefs->refs, refname, &debug_print_reflog_ent, &dbg); |
319 | 0 | trace_printf_key(&trace_refs, "for_each_reflog: %s: %d\n", refname, res); |
320 | 0 | return res; |
321 | 0 | } |
322 | | |
323 | | static int debug_for_each_reflog_ent_reverse(struct ref_store *ref_store, |
324 | | const char *refname, |
325 | | each_reflog_ent_fn fn, |
326 | | void *cb_data) |
327 | 0 | { |
328 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
329 | 0 | struct debug_reflog dbg = { |
330 | 0 | .refname = refname, |
331 | 0 | .fn = fn, |
332 | 0 | .cb_data = cb_data, |
333 | 0 | }; |
334 | 0 | int res = drefs->refs->be->for_each_reflog_ent_reverse( |
335 | 0 | drefs->refs, refname, &debug_print_reflog_ent, &dbg); |
336 | 0 | trace_printf_key(&trace_refs, "for_each_reflog_reverse: %s: %d\n", refname, res); |
337 | 0 | return res; |
338 | 0 | } |
339 | | |
340 | | static int debug_reflog_exists(struct ref_store *ref_store, const char *refname) |
341 | 0 | { |
342 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
343 | 0 | int res = drefs->refs->be->reflog_exists(drefs->refs, refname); |
344 | 0 | trace_printf_key(&trace_refs, "reflog_exists: %s: %d\n", refname, res); |
345 | 0 | return res; |
346 | 0 | } |
347 | | |
348 | | static int debug_create_reflog(struct ref_store *ref_store, const char *refname, |
349 | | struct strbuf *err) |
350 | 0 | { |
351 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
352 | 0 | int res = drefs->refs->be->create_reflog(drefs->refs, refname, err); |
353 | 0 | trace_printf_key(&trace_refs, "create_reflog: %s: %d\n", refname, res); |
354 | 0 | return res; |
355 | 0 | } |
356 | | |
357 | | static int debug_delete_reflog(struct ref_store *ref_store, const char *refname) |
358 | 0 | { |
359 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
360 | 0 | int res = drefs->refs->be->delete_reflog(drefs->refs, refname); |
361 | 0 | trace_printf_key(&trace_refs, "delete_reflog: %s: %d\n", refname, res); |
362 | 0 | return res; |
363 | 0 | } |
364 | | |
365 | | struct debug_reflog_expiry_should_prune { |
366 | | reflog_expiry_prepare_fn *prepare; |
367 | | reflog_expiry_should_prune_fn *should_prune; |
368 | | reflog_expiry_cleanup_fn *cleanup; |
369 | | void *cb_data; |
370 | | }; |
371 | | |
372 | | static void debug_reflog_expiry_prepare(const char *refname, |
373 | | const struct object_id *oid, |
374 | | void *cb_data) |
375 | 0 | { |
376 | 0 | struct debug_reflog_expiry_should_prune *prune = cb_data; |
377 | 0 | trace_printf_key(&trace_refs, "reflog_expire_prepare: %s\n", refname); |
378 | 0 | prune->prepare(refname, oid, prune->cb_data); |
379 | 0 | } |
380 | | |
381 | | static int debug_reflog_expiry_should_prune_fn(struct object_id *ooid, |
382 | | struct object_id *noid, |
383 | | const char *email, |
384 | | timestamp_t timestamp, int tz, |
385 | 0 | const char *message, void *cb_data) { |
386 | 0 | struct debug_reflog_expiry_should_prune *prune = cb_data; |
387 | |
|
388 | 0 | int result = prune->should_prune(ooid, noid, email, timestamp, tz, message, prune->cb_data); |
389 | 0 | trace_printf_key(&trace_refs, "reflog_expire_should_prune: %s %ld: %d\n", message, (long int) timestamp, result); |
390 | 0 | return result; |
391 | 0 | } |
392 | | |
393 | | static void debug_reflog_expiry_cleanup(void *cb_data) |
394 | 0 | { |
395 | 0 | struct debug_reflog_expiry_should_prune *prune = cb_data; |
396 | 0 | prune->cleanup(prune->cb_data); |
397 | 0 | } |
398 | | |
399 | | static int debug_reflog_expire(struct ref_store *ref_store, const char *refname, |
400 | | unsigned int flags, |
401 | | reflog_expiry_prepare_fn prepare_fn, |
402 | | reflog_expiry_should_prune_fn should_prune_fn, |
403 | | reflog_expiry_cleanup_fn cleanup_fn, |
404 | | void *policy_cb_data) |
405 | 0 | { |
406 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
407 | 0 | struct debug_reflog_expiry_should_prune prune = { |
408 | 0 | .prepare = prepare_fn, |
409 | 0 | .cleanup = cleanup_fn, |
410 | 0 | .should_prune = should_prune_fn, |
411 | 0 | .cb_data = policy_cb_data, |
412 | 0 | }; |
413 | 0 | int res = drefs->refs->be->reflog_expire(drefs->refs, refname, |
414 | 0 | flags, &debug_reflog_expiry_prepare, |
415 | 0 | &debug_reflog_expiry_should_prune_fn, |
416 | 0 | &debug_reflog_expiry_cleanup, |
417 | 0 | &prune); |
418 | 0 | trace_printf_key(&trace_refs, "reflog_expire: %s: %d\n", refname, res); |
419 | 0 | return res; |
420 | 0 | } |
421 | | |
422 | | static int debug_fsck(struct ref_store *ref_store, |
423 | | struct fsck_options *o) |
424 | 0 | { |
425 | 0 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; |
426 | 0 | int res = drefs->refs->be->fsck(drefs->refs, o); |
427 | 0 | trace_printf_key(&trace_refs, "fsck: %d\n", res); |
428 | 0 | return res; |
429 | 0 | } |
430 | | |
431 | | struct ref_storage_be refs_be_debug = { |
432 | | .name = "debug", |
433 | | .init = NULL, |
434 | | .release = debug_release, |
435 | | .create_on_disk = debug_create_on_disk, |
436 | | |
437 | | /* |
438 | | * None of these should be NULL. If the "files" backend (in |
439 | | * "struct ref_storage_be refs_be_files" in files-backend.c) |
440 | | * has a function we should also have a wrapper for it here. |
441 | | * Test the output with "GIT_TRACE_REFS=1". |
442 | | */ |
443 | | .transaction_prepare = debug_transaction_prepare, |
444 | | .transaction_finish = debug_transaction_finish, |
445 | | .transaction_abort = debug_transaction_abort, |
446 | | .initial_transaction_commit = debug_initial_transaction_commit, |
447 | | |
448 | | .pack_refs = debug_pack_refs, |
449 | | .rename_ref = debug_rename_ref, |
450 | | .copy_ref = debug_copy_ref, |
451 | | |
452 | | .iterator_begin = debug_ref_iterator_begin, |
453 | | .read_raw_ref = debug_read_raw_ref, |
454 | | .read_symbolic_ref = debug_read_symbolic_ref, |
455 | | |
456 | | .reflog_iterator_begin = debug_reflog_iterator_begin, |
457 | | .for_each_reflog_ent = debug_for_each_reflog_ent, |
458 | | .for_each_reflog_ent_reverse = debug_for_each_reflog_ent_reverse, |
459 | | .reflog_exists = debug_reflog_exists, |
460 | | .create_reflog = debug_create_reflog, |
461 | | .delete_reflog = debug_delete_reflog, |
462 | | .reflog_expire = debug_reflog_expire, |
463 | | |
464 | | .fsck = debug_fsck, |
465 | | }; |