@matheusbsbs / matheus-bagliano / commits / 4441f42707
Fork 0

refs: add GIT_TRACE_REFS debugging mechanism

When set in the environment, GIT_TRACE_REFS makes git print operations and results as they flow through the ref storage backend. This helps debug discrepancies between different ref backends. Example: $ GIT_TRACE_REFS="1" ./git branch 15:42:09.769631 refs/debug.c:26 ref_store for .git 15:42:09.769681 refs/debug.c:249 read_raw_ref: HEAD: 0000000000000000000000000000000000000000 (=> refs/heads/ref-debug) type 1: 0 15:42:09.769695 refs/debug.c:249 read_raw_ref: refs/heads/ref-debug: 3a238e539bcdfe3f9eb5010fd218640c1b499f7a (=> refs/heads/ref-debug) type 0: 0 15:42:09.770282 refs/debug.c:233 ref_iterator_begin: refs/heads/ (0x1) 15:42:09.770290 refs/debug.c:189 iterator_advance: refs/heads/b4 (0) 15:42:09.770295 refs/debug.c:189 iterator_advance: refs/heads/branch3 (0) Signed-off-by: Han-Wen Nienhuys <hanwen@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Han-Wen Nienhuys committed Sep 9, 2020 at 10:15 UTC 4441f4270758042cc38ce8c04e4350ada743b28a
5 files changed +409
Documentation/git.txt
+4
@@ -722,6 +722,10 @@ of clones and fetches.
722 time of each Git command.
723 See `GIT_TRACE` for available trace output options.
724
725 +`GIT_TRACE_REFS`::
726 + Enables trace messages for operations on the ref database.
727 + See `GIT_TRACE` for available trace output options.
728 +
729 `GIT_TRACE_SETUP`::
730 Enables trace messages printing the .git, working tree and current
731 working directory after Git has completed its setup phase.
Makefile
+1
@@ -950,6 +950,7 @@ LIB_OBJS += rebase.o
950 LIB_OBJS += ref-filter.o
951 LIB_OBJS += reflog-walk.o
952 LIB_OBJS += refs.o
953 +LIB_OBJS += refs/debug.o
954 LIB_OBJS += refs/files-backend.o
955 LIB_OBJS += refs/iterator.o
956 LIB_OBJS += refs/packed-backend.o
refs.c
+1
@@ -1774,6 +1774,7 @@ struct ref_store *get_main_ref_store(struct repository *r)
1774 BUG("attempting to get main_ref_store outside of repository");
1775
1776 r->refs_private = ref_store_init(r->gitdir, REF_STORE_ALL_CAPS);
1777 + r->refs_private = maybe_debug_wrap_ref_store(r->gitdir, r->refs_private);
1778 return r->refs_private;
1779 }
1780
refs/debug.c new
+398
@@ -0,0 +1,398 @@
1 +
2 +#include "refs-internal.h"
3 +#include "trace.h"
4 +
5 +static struct trace_key trace_refs = TRACE_KEY_INIT(REFS);
6 +
7 +struct debug_ref_store {
8 + struct ref_store base;
9 + struct ref_store *refs;
10 +};
11 +
12 +extern struct ref_storage_be refs_be_debug;
13 +
14 +struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_store *store)
15 +{
16 + struct debug_ref_store *res;
17 + struct ref_storage_be *be_copy;
18 +
19 + if (!trace_want(&trace_refs)) {
20 + return store;
21 + }
22 + res = xmalloc(sizeof(struct debug_ref_store));
23 + be_copy = xmalloc(sizeof(*be_copy));
24 + *be_copy = refs_be_debug;
25 + /* we never deallocate backends, so safe to copy the pointer. */
26 + be_copy->name = store->be->name;
27 + trace_printf_key(&trace_refs, "ref_store for %s\n", gitdir);
28 + res->refs = store;
29 + base_ref_store_init((struct ref_store *)res, be_copy);
30 + return (struct ref_store *)res;
31 +}
32 +
33 +static int debug_init_db(struct ref_store *refs, struct strbuf *err)
34 +{
35 + struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
36 + int res = drefs->refs->be->init_db(drefs->refs, err);
37 + trace_printf_key(&trace_refs, "init_db: %d\n", res);
38 + return res;
39 +}
40 +
41 +static int debug_transaction_prepare(struct ref_store *refs,
42 + struct ref_transaction *transaction,
43 + struct strbuf *err)
44 +{
45 + struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
46 + int res;
47 + transaction->ref_store = drefs->refs;
48 + res = drefs->refs->be->transaction_prepare(drefs->refs, transaction,
49 + err);
50 + trace_printf_key(&trace_refs, "transaction_prepare: %d\n", res);
51 + return res;
52 +}
53 +
54 +static void print_update(int i, const char *refname,
55 + const struct object_id *old_oid,
56 + const struct object_id *new_oid, unsigned int flags,
57 + unsigned int type, const char *msg)
58 +{
59 + char o[GIT_MAX_HEXSZ + 1] = "null";
60 + char n[GIT_MAX_HEXSZ + 1] = "null";
61 + if (old_oid)
62 + oid_to_hex_r(o, old_oid);
63 + if (new_oid)
64 + oid_to_hex_r(n, new_oid);
65 +
66 + type &= 0xf; /* see refs.h REF_* */
67 + flags &= REF_HAVE_NEW | REF_HAVE_OLD | REF_NO_DEREF |
68 + REF_FORCE_CREATE_REFLOG;
69 + trace_printf_key(&trace_refs, "%d: %s %s -> %s (F=0x%x, T=0x%x) \"%s\"\n", i, refname,
70 + o, n, flags, type, msg);
71 +}
72 +
73 +static void print_transaction(struct ref_transaction *transaction)
74 +{
75 + int i;
76 + trace_printf_key(&trace_refs, "transaction {\n");
77 + for (i = 0; i < transaction->nr; i++) {
78 + struct ref_update *u = transaction->updates[i];
79 + print_update(i, u->refname, &u->old_oid, &u->new_oid, u->flags,
80 + u->type, u->msg);
81 + }
82 + trace_printf_key(&trace_refs, "}\n");
83 +}
84 +
85 +static int debug_transaction_finish(struct ref_store *refs,
86 + struct ref_transaction *transaction,
87 + struct strbuf *err)
88 +{
89 + struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
90 + int res;
91 + transaction->ref_store = drefs->refs;
92 + res = drefs->refs->be->transaction_finish(drefs->refs, transaction,
93 + err);
94 + print_transaction(transaction);
95 + trace_printf_key(&trace_refs, "finish: %d\n", res);
96 + return res;
97 +}
98 +
99 +static int debug_transaction_abort(struct ref_store *refs,
100 + struct ref_transaction *transaction,
101 + struct strbuf *err)
102 +{
103 + struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
104 + int res;
105 + transaction->ref_store = drefs->refs;
106 + res = drefs->refs->be->transaction_abort(drefs->refs, transaction, err);
107 + return res;
108 +}
109 +
110 +static int debug_initial_transaction_commit(struct ref_store *refs,
111 + struct ref_transaction *transaction,
112 + struct strbuf *err)
113 +{
114 + struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
115 + int res;
116 + transaction->ref_store = drefs->refs;
117 + res = drefs->refs->be->initial_transaction_commit(drefs->refs,
118 + transaction, err);
119 + return res;
120 +}
121 +
122 +static int debug_pack_refs(struct ref_store *ref_store, unsigned int flags)
123 +{
124 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
125 + int res = drefs->refs->be->pack_refs(drefs->refs, flags);
126 + trace_printf_key(&trace_refs, "pack_refs: %d\n", res);
127 + return res;
128 +}
129 +
130 +static int debug_create_symref(struct ref_store *ref_store,
131 + const char *ref_name, const char *target,
132 + const char *logmsg)
133 +{
134 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
135 + int res = drefs->refs->be->create_symref(drefs->refs, ref_name, target,
136 + logmsg);
137 + trace_printf_key(&trace_refs, "create_symref: %s -> %s \"%s\": %d\n", ref_name,
138 + target, logmsg, res);
139 + return res;
140 +}
141 +
142 +static int debug_delete_refs(struct ref_store *ref_store, const char *msg,
143 + struct string_list *refnames, unsigned int flags)
144 +{
145 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
146 + int res =
147 + drefs->refs->be->delete_refs(drefs->refs, msg, refnames, flags);
148 + int i;
149 + trace_printf_key(&trace_refs, "delete_refs {\n");
150 + for (i = 0; i < refnames->nr; i++)
151 + trace_printf_key(&trace_refs, "%s\n", refnames->items[i].string);
152 + trace_printf_key(&trace_refs, "}: %d\n", res);
153 + return res;
154 +}
155 +
156 +static int debug_rename_ref(struct ref_store *ref_store, const char *oldref,
157 + const char *newref, const char *logmsg)
158 +{
159 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
160 + int res = drefs->refs->be->rename_ref(drefs->refs, oldref, newref,
161 + logmsg);
162 + trace_printf_key(&trace_refs, "rename_ref: %s -> %s \"%s\": %d\n", oldref, newref,
163 + logmsg, res);
164 + return res;
165 +}
166 +
167 +static int debug_copy_ref(struct ref_store *ref_store, const char *oldref,
168 + const char *newref, const char *logmsg)
169 +{
170 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
171 + int res =
172 + drefs->refs->be->copy_ref(drefs->refs, oldref, newref, logmsg);
173 + trace_printf_key(&trace_refs, "copy_ref: %s -> %s \"%s\": %d\n", oldref, newref,
174 + logmsg, res);
175 + return res;
176 +}
177 +
178 +struct debug_ref_iterator {
179 + struct ref_iterator base;
180 + struct ref_iterator *iter;
181 +};
182 +
183 +static int debug_ref_iterator_advance(struct ref_iterator *ref_iterator)
184 +{
185 + struct debug_ref_iterator *diter =
186 + (struct debug_ref_iterator *)ref_iterator;
187 + int res = diter->iter->vtable->advance(diter->iter);
188 + if (res)
189 + trace_printf_key(&trace_refs, "iterator_advance: (%d)\n", res);
190 + else
191 + trace_printf_key(&trace_refs, "iterator_advance: %s (0)\n",
192 + diter->iter->refname);
193 +
194 + diter->base.ordered = diter->iter->ordered;
195 + diter->base.refname = diter->iter->refname;
196 + diter->base.oid = diter->iter->oid;
197 + diter->base.flags = diter->iter->flags;
198 + return res;
199 +}
200 +
201 +static int debug_ref_iterator_peel(struct ref_iterator *ref_iterator,
202 + struct object_id *peeled)
203 +{
204 + struct debug_ref_iterator *diter =
205 + (struct debug_ref_iterator *)ref_iterator;
206 + int res = diter->iter->vtable->peel(diter->iter, peeled);
207 + trace_printf_key(&trace_refs, "iterator_peel: %s: %d\n", diter->iter->refname, res);
208 + return res;
209 +}
210 +
211 +static int debug_ref_iterator_abort(struct ref_iterator *ref_iterator)
212 +{
213 + struct debug_ref_iterator *diter =
214 + (struct debug_ref_iterator *)ref_iterator;
215 + int res = diter->iter->vtable->abort(diter->iter);
216 + trace_printf_key(&trace_refs, "iterator_abort: %d\n", res);
217 + return res;
218 +}
219 +
220 +static struct ref_iterator_vtable debug_ref_iterator_vtable = {
221 + debug_ref_iterator_advance, debug_ref_iterator_peel,
222 + debug_ref_iterator_abort
223 +};
224 +
225 +static struct ref_iterator *
226 +debug_ref_iterator_begin(struct ref_store *ref_store, const char *prefix,
227 + unsigned int flags)
228 +{
229 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
230 + struct ref_iterator *res =
231 + drefs->refs->be->iterator_begin(drefs->refs, prefix, flags);
232 + struct debug_ref_iterator *diter = xcalloc(1, sizeof(*diter));
233 + base_ref_iterator_init(&diter->base, &debug_ref_iterator_vtable, 1);
234 + diter->iter = res;
235 + trace_printf_key(&trace_refs, "ref_iterator_begin: %s (0x%x)\n", prefix, flags);
236 + return &diter->base;
237 +}
238 +
239 +static int debug_read_raw_ref(struct ref_store *ref_store, const char *refname,
240 + struct object_id *oid, struct strbuf *referent,
241 + unsigned int *type)
242 +{
243 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
244 + int res = 0;
245 +
246 + oidcpy(oid, &null_oid);
247 + res = drefs->refs->be->read_raw_ref(drefs->refs, refname, oid, referent,
248 + type);
249 +
250 + if (res == 0) {
251 + trace_printf_key(&trace_refs, "read_raw_ref: %s: %s (=> %s) type %x: %d\n",
252 + refname, oid_to_hex(oid), referent->buf, *type, res);
253 + } else {
254 + trace_printf_key(&trace_refs, "read_raw_ref: %s: %d\n", refname, res);
255 + }
256 + return res;
257 +}
258 +
259 +static struct ref_iterator *
260 +debug_reflog_iterator_begin(struct ref_store *ref_store)
261 +{
262 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
263 + struct ref_iterator *res =
264 + drefs->refs->be->reflog_iterator_begin(drefs->refs);
265 + trace_printf_key(&trace_refs, "for_each_reflog_iterator_begin\n");
266 + return res;
267 +}
268 +
269 +struct debug_reflog {
270 + const char *refname;
271 + each_reflog_ent_fn *fn;
272 + void *cb_data;
273 +};
274 +
275 +static int debug_print_reflog_ent(struct object_id *old_oid,
276 + struct object_id *new_oid,
277 + const char *committer, timestamp_t timestamp,
278 + int tz, const char *msg, void *cb_data)
279 +{
280 + struct debug_reflog *dbg = (struct debug_reflog *)cb_data;
281 + int ret;
282 + char o[GIT_MAX_HEXSZ + 1] = "null";
283 + char n[GIT_MAX_HEXSZ + 1] = "null";
284 + if (old_oid)
285 + oid_to_hex_r(o, old_oid);
286 + if (new_oid)
287 + oid_to_hex_r(n, new_oid);
288 +
289 + ret = dbg->fn(old_oid, new_oid, committer, timestamp, tz, msg,
290 + dbg->cb_data);
291 + trace_printf_key(&trace_refs, "reflog_ent %s (ret %d): %s -> %s, %s %ld \"%s\"\n",
292 + dbg->refname, ret, o, n, committer, (long int)timestamp, msg);
293 + return ret;
294 +}
295 +
296 +static int debug_for_each_reflog_ent(struct ref_store *ref_store,
297 + const char *refname, each_reflog_ent_fn fn,
298 + void *cb_data)
299 +{
300 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
301 + struct debug_reflog dbg = {
302 + .refname = refname,
303 + .fn = fn,
304 + .cb_data = cb_data,
305 + };
306 +
307 + int res = drefs->refs->be->for_each_reflog_ent(
308 + drefs->refs, refname, &debug_print_reflog_ent, &dbg);
309 + trace_printf_key(&trace_refs, "for_each_reflog: %s: %d\n", refname, res);
310 + return res;
311 +}
312 +
313 +static int debug_for_each_reflog_ent_reverse(struct ref_store *ref_store,
314 + const char *refname,
315 + each_reflog_ent_fn fn,
316 + void *cb_data)
317 +{
318 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
319 + struct debug_reflog dbg = {
320 + .refname = refname,
321 + .fn = fn,
322 + .cb_data = cb_data,
323 + };
324 + int res = drefs->refs->be->for_each_reflog_ent_reverse(
325 + drefs->refs, refname, &debug_print_reflog_ent, &dbg);
326 + trace_printf_key(&trace_refs, "for_each_reflog_reverse: %s: %d\n", refname, res);
327 + return res;
328 +}
329 +
330 +static int debug_reflog_exists(struct ref_store *ref_store, const char *refname)
331 +{
332 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
333 + int res = drefs->refs->be->reflog_exists(drefs->refs, refname);
334 + trace_printf_key(&trace_refs, "reflog_exists: %s: %d\n", refname, res);
335 + return res;
336 +}
337 +
338 +static int debug_create_reflog(struct ref_store *ref_store, const char *refname,
339 + int force_create, struct strbuf *err)
340 +{
341 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
342 + int res = drefs->refs->be->create_reflog(drefs->refs, refname,
343 + force_create, err);
344 + trace_printf_key(&trace_refs, "create_reflog: %s: %d\n", refname, res);
345 + return res;
346 +}
347 +
348 +static int debug_delete_reflog(struct ref_store *ref_store, const char *refname)
349 +{
350 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
351 + int res = drefs->refs->be->delete_reflog(drefs->refs, refname);
352 + trace_printf_key(&trace_refs, "delete_reflog: %s: %d\n", refname, res);
353 + return res;
354 +}
355 +
356 +static int debug_reflog_expire(struct ref_store *ref_store, const char *refname,
357 + const struct object_id *oid, unsigned int flags,
358 + reflog_expiry_prepare_fn prepare_fn,
359 + reflog_expiry_should_prune_fn should_prune_fn,
360 + reflog_expiry_cleanup_fn cleanup_fn,
361 + void *policy_cb_data)
362 +{
363 + struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
364 + int res = drefs->refs->be->reflog_expire(drefs->refs, refname, oid,
365 + flags, prepare_fn,
366 + should_prune_fn, cleanup_fn,
367 + policy_cb_data);
368 + trace_printf_key(&trace_refs, "reflog_expire: %s: %d\n", refname, res);
369 + return res;
370 +}
371 +
372 +struct ref_storage_be refs_be_debug = {
373 + NULL,
374 + "debug",
375 + NULL,
376 + debug_init_db,
377 + debug_transaction_prepare,
378 + debug_transaction_finish,
379 + debug_transaction_abort,
380 + debug_initial_transaction_commit,
381 +
382 + debug_pack_refs,
383 + debug_create_symref,
384 + debug_delete_refs,
385 + debug_rename_ref,
386 + debug_copy_ref,
387 +
388 + debug_ref_iterator_begin,
389 + debug_read_raw_ref,
390 +
391 + debug_reflog_iterator_begin,
392 + debug_for_each_reflog_ent,
393 + debug_for_each_reflog_ent_reverse,
394 + debug_reflog_exists,
395 + debug_create_reflog,
396 + debug_delete_reflog,
397 + debug_reflog_expire,
398 +};
refs/refs-internal.h
+5
@@ -690,4 +690,9 @@ int parse_loose_ref_contents(const char *buf, struct object_id *oid,
690 void base_ref_store_init(struct ref_store *refs,
691 const struct ref_storage_be *be);
692
693 +/*
694 + * Support GIT_TRACE_REFS by optionally wrapping the given ref_store instance.
695 + */
696 +struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_store *store);
697 +
698 #endif /* REFS_REFS_INTERNAL_H */