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