]>
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 | ||
126 | static int debug_pack_refs(struct ref_store *ref_store, unsigned int flags) | |
127 | { | |
128 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
129 | int res = drefs->refs->be->pack_refs(drefs->refs, flags); | |
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 | ||
146 | static int debug_delete_refs(struct ref_store *ref_store, const char *msg, | |
147 | struct string_list *refnames, unsigned int flags) | |
148 | { | |
149 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
150 | int res = | |
151 | drefs->refs->be->delete_refs(drefs->refs, msg, refnames, flags); | |
152 | int i; | |
153 | trace_printf_key(&trace_refs, "delete_refs {\n"); | |
154 | for (i = 0; i < refnames->nr; i++) | |
155 | trace_printf_key(&trace_refs, "%s\n", refnames->items[i].string); | |
156 | trace_printf_key(&trace_refs, "}: %d\n", res); | |
157 | return res; | |
158 | } | |
159 | ||
160 | static int debug_rename_ref(struct ref_store *ref_store, const char *oldref, | |
161 | const char *newref, const char *logmsg) | |
162 | { | |
163 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
164 | int res = drefs->refs->be->rename_ref(drefs->refs, oldref, newref, | |
165 | logmsg); | |
166 | trace_printf_key(&trace_refs, "rename_ref: %s -> %s \"%s\": %d\n", oldref, newref, | |
167 | logmsg, res); | |
168 | return res; | |
169 | } | |
170 | ||
171 | static int debug_copy_ref(struct ref_store *ref_store, const char *oldref, | |
172 | const char *newref, const char *logmsg) | |
173 | { | |
174 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
175 | int res = | |
176 | drefs->refs->be->copy_ref(drefs->refs, oldref, newref, logmsg); | |
177 | trace_printf_key(&trace_refs, "copy_ref: %s -> %s \"%s\": %d\n", oldref, newref, | |
178 | logmsg, res); | |
179 | return res; | |
180 | } | |
181 | ||
182 | struct debug_ref_iterator { | |
183 | struct ref_iterator base; | |
184 | struct ref_iterator *iter; | |
185 | }; | |
186 | ||
187 | static int debug_ref_iterator_advance(struct ref_iterator *ref_iterator) | |
188 | { | |
189 | struct debug_ref_iterator *diter = | |
190 | (struct debug_ref_iterator *)ref_iterator; | |
191 | int res = diter->iter->vtable->advance(diter->iter); | |
192 | if (res) | |
193 | trace_printf_key(&trace_refs, "iterator_advance: (%d)\n", res); | |
194 | else | |
195 | trace_printf_key(&trace_refs, "iterator_advance: %s (0)\n", | |
196 | diter->iter->refname); | |
197 | ||
198 | diter->base.ordered = diter->iter->ordered; | |
199 | diter->base.refname = diter->iter->refname; | |
200 | diter->base.oid = diter->iter->oid; | |
201 | diter->base.flags = diter->iter->flags; | |
202 | return res; | |
203 | } | |
204 | ||
205 | static int debug_ref_iterator_peel(struct ref_iterator *ref_iterator, | |
206 | struct object_id *peeled) | |
207 | { | |
208 | struct debug_ref_iterator *diter = | |
209 | (struct debug_ref_iterator *)ref_iterator; | |
210 | int res = diter->iter->vtable->peel(diter->iter, peeled); | |
211 | trace_printf_key(&trace_refs, "iterator_peel: %s: %d\n", diter->iter->refname, res); | |
212 | return res; | |
213 | } | |
214 | ||
215 | static int debug_ref_iterator_abort(struct ref_iterator *ref_iterator) | |
216 | { | |
217 | struct debug_ref_iterator *diter = | |
218 | (struct debug_ref_iterator *)ref_iterator; | |
219 | int res = diter->iter->vtable->abort(diter->iter); | |
220 | trace_printf_key(&trace_refs, "iterator_abort: %d\n", res); | |
221 | return res; | |
222 | } | |
223 | ||
224 | static struct ref_iterator_vtable debug_ref_iterator_vtable = { | |
e2f8acb6 ÆAB |
225 | .advance = debug_ref_iterator_advance, |
226 | .peel = debug_ref_iterator_peel, | |
227 | .abort = debug_ref_iterator_abort, | |
4441f427 HWN |
228 | }; |
229 | ||
230 | static struct ref_iterator * | |
231 | debug_ref_iterator_begin(struct ref_store *ref_store, const char *prefix, | |
232 | unsigned int flags) | |
233 | { | |
234 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
235 | struct ref_iterator *res = | |
236 | drefs->refs->be->iterator_begin(drefs->refs, prefix, flags); | |
237 | struct debug_ref_iterator *diter = xcalloc(1, sizeof(*diter)); | |
238 | base_ref_iterator_init(&diter->base, &debug_ref_iterator_vtable, 1); | |
239 | diter->iter = res; | |
c510928a HWN |
240 | trace_printf_key(&trace_refs, "ref_iterator_begin: \"%s\" (0x%x)\n", |
241 | prefix, flags); | |
4441f427 HWN |
242 | return &diter->base; |
243 | } | |
244 | ||
245 | static int debug_read_raw_ref(struct ref_store *ref_store, const char *refname, | |
246 | struct object_id *oid, struct strbuf *referent, | |
5b12e16b | 247 | unsigned int *type, int *failure_errno) |
4441f427 HWN |
248 | { |
249 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
250 | int res = 0; | |
251 | ||
14228447 | 252 | oidcpy(oid, null_oid()); |
4441f427 | 253 | res = drefs->refs->be->read_raw_ref(drefs->refs, refname, oid, referent, |
5b12e16b | 254 | type, failure_errno); |
4441f427 HWN |
255 | |
256 | if (res == 0) { | |
257 | trace_printf_key(&trace_refs, "read_raw_ref: %s: %s (=> %s) type %x: %d\n", | |
258 | refname, oid_to_hex(oid), referent->buf, *type, res); | |
259 | } else { | |
2a2112a4 HWN |
260 | trace_printf_key(&trace_refs, |
261 | "read_raw_ref: %s: %d (errno %d)\n", refname, | |
5b12e16b | 262 | res, *failure_errno); |
4441f427 HWN |
263 | } |
264 | return res; | |
265 | } | |
266 | ||
5b875404 ÆAB |
267 | static int debug_read_symbolic_ref(struct ref_store *ref_store, const char *refname, |
268 | struct strbuf *referent) | |
269 | { | |
270 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
271 | struct ref_store *refs = drefs->refs; | |
272 | int res; | |
273 | ||
274 | res = refs->be->read_symbolic_ref(refs, refname, referent); | |
275 | if (!res) | |
276 | trace_printf_key(&trace_refs, "read_symbolic_ref: %s: (%s)\n", | |
277 | refname, referent->buf); | |
278 | else | |
279 | trace_printf_key(&trace_refs, | |
280 | "read_symbolic_ref: %s: %d\n", refname, res); | |
281 | return res; | |
282 | ||
283 | } | |
284 | ||
4441f427 HWN |
285 | static struct ref_iterator * |
286 | debug_reflog_iterator_begin(struct ref_store *ref_store) | |
287 | { | |
288 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
289 | struct ref_iterator *res = | |
290 | drefs->refs->be->reflog_iterator_begin(drefs->refs); | |
291 | trace_printf_key(&trace_refs, "for_each_reflog_iterator_begin\n"); | |
292 | return res; | |
293 | } | |
294 | ||
295 | struct debug_reflog { | |
296 | const char *refname; | |
297 | each_reflog_ent_fn *fn; | |
298 | void *cb_data; | |
299 | }; | |
300 | ||
301 | static int debug_print_reflog_ent(struct object_id *old_oid, | |
302 | struct object_id *new_oid, | |
303 | const char *committer, timestamp_t timestamp, | |
304 | int tz, const char *msg, void *cb_data) | |
305 | { | |
306 | struct debug_reflog *dbg = (struct debug_reflog *)cb_data; | |
307 | int ret; | |
308 | char o[GIT_MAX_HEXSZ + 1] = "null"; | |
309 | char n[GIT_MAX_HEXSZ + 1] = "null"; | |
65279256 | 310 | char *msgend = strchrnul(msg, '\n'); |
4441f427 HWN |
311 | if (old_oid) |
312 | oid_to_hex_r(o, old_oid); | |
313 | if (new_oid) | |
314 | oid_to_hex_r(n, new_oid); | |
315 | ||
316 | ret = dbg->fn(old_oid, new_oid, committer, timestamp, tz, msg, | |
317 | dbg->cb_data); | |
65279256 HWN |
318 | trace_printf_key(&trace_refs, |
319 | "reflog_ent %s (ret %d): %s -> %s, %s %ld \"%.*s\"\n", | |
320 | dbg->refname, ret, o, n, committer, | |
321 | (long int)timestamp, (int)(msgend - msg), msg); | |
4441f427 HWN |
322 | return ret; |
323 | } | |
324 | ||
325 | static int debug_for_each_reflog_ent(struct ref_store *ref_store, | |
326 | const char *refname, each_reflog_ent_fn fn, | |
327 | void *cb_data) | |
328 | { | |
329 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
330 | struct debug_reflog dbg = { | |
331 | .refname = refname, | |
332 | .fn = fn, | |
333 | .cb_data = cb_data, | |
334 | }; | |
335 | ||
336 | int res = drefs->refs->be->for_each_reflog_ent( | |
337 | drefs->refs, refname, &debug_print_reflog_ent, &dbg); | |
338 | trace_printf_key(&trace_refs, "for_each_reflog: %s: %d\n", refname, res); | |
339 | return res; | |
340 | } | |
341 | ||
342 | static int debug_for_each_reflog_ent_reverse(struct ref_store *ref_store, | |
343 | const char *refname, | |
344 | each_reflog_ent_fn fn, | |
345 | void *cb_data) | |
346 | { | |
347 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
348 | struct debug_reflog dbg = { | |
349 | .refname = refname, | |
350 | .fn = fn, | |
351 | .cb_data = cb_data, | |
352 | }; | |
353 | int res = drefs->refs->be->for_each_reflog_ent_reverse( | |
354 | drefs->refs, refname, &debug_print_reflog_ent, &dbg); | |
355 | trace_printf_key(&trace_refs, "for_each_reflog_reverse: %s: %d\n", refname, res); | |
356 | return res; | |
357 | } | |
358 | ||
359 | static int debug_reflog_exists(struct ref_store *ref_store, const char *refname) | |
360 | { | |
361 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
362 | int res = drefs->refs->be->reflog_exists(drefs->refs, refname); | |
363 | trace_printf_key(&trace_refs, "reflog_exists: %s: %d\n", refname, res); | |
364 | return res; | |
365 | } | |
366 | ||
367 | static int debug_create_reflog(struct ref_store *ref_store, const char *refname, | |
7b089120 | 368 | struct strbuf *err) |
4441f427 HWN |
369 | { |
370 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
7b089120 | 371 | int res = drefs->refs->be->create_reflog(drefs->refs, refname, err); |
4441f427 HWN |
372 | trace_printf_key(&trace_refs, "create_reflog: %s: %d\n", refname, res); |
373 | return res; | |
374 | } | |
375 | ||
376 | static int debug_delete_reflog(struct ref_store *ref_store, const char *refname) | |
377 | { | |
378 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
379 | int res = drefs->refs->be->delete_reflog(drefs->refs, refname); | |
380 | trace_printf_key(&trace_refs, "delete_reflog: %s: %d\n", refname, res); | |
381 | return res; | |
382 | } | |
383 | ||
34c31997 HWN |
384 | struct debug_reflog_expiry_should_prune { |
385 | reflog_expiry_prepare_fn *prepare; | |
386 | reflog_expiry_should_prune_fn *should_prune; | |
387 | reflog_expiry_cleanup_fn *cleanup; | |
388 | void *cb_data; | |
389 | }; | |
390 | ||
391 | static void debug_reflog_expiry_prepare(const char *refname, | |
81bc1225 ÆAB |
392 | const struct object_id *oid, |
393 | void *cb_data) | |
34c31997 HWN |
394 | { |
395 | struct debug_reflog_expiry_should_prune *prune = cb_data; | |
396 | trace_printf_key(&trace_refs, "reflog_expire_prepare: %s\n", refname); | |
397 | prune->prepare(refname, oid, prune->cb_data); | |
398 | } | |
399 | ||
400 | static int debug_reflog_expiry_should_prune_fn(struct object_id *ooid, | |
401 | struct object_id *noid, | |
402 | const char *email, | |
403 | timestamp_t timestamp, int tz, | |
404 | const char *message, void *cb_data) { | |
405 | struct debug_reflog_expiry_should_prune *prune = cb_data; | |
406 | ||
407 | int result = prune->should_prune(ooid, noid, email, timestamp, tz, message, prune->cb_data); | |
408 | trace_printf_key(&trace_refs, "reflog_expire_should_prune: %s %ld: %d\n", message, (long int) timestamp, result); | |
409 | return result; | |
410 | } | |
411 | ||
412 | static void debug_reflog_expiry_cleanup(void *cb_data) | |
413 | { | |
414 | struct debug_reflog_expiry_should_prune *prune = cb_data; | |
415 | prune->cleanup(prune->cb_data); | |
416 | } | |
417 | ||
4441f427 | 418 | static int debug_reflog_expire(struct ref_store *ref_store, const char *refname, |
cc40b5ce | 419 | unsigned int flags, |
4441f427 HWN |
420 | reflog_expiry_prepare_fn prepare_fn, |
421 | reflog_expiry_should_prune_fn should_prune_fn, | |
422 | reflog_expiry_cleanup_fn cleanup_fn, | |
423 | void *policy_cb_data) | |
424 | { | |
425 | struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; | |
34c31997 HWN |
426 | struct debug_reflog_expiry_should_prune prune = { |
427 | .prepare = prepare_fn, | |
428 | .cleanup = cleanup_fn, | |
429 | .should_prune = should_prune_fn, | |
430 | .cb_data = policy_cb_data, | |
431 | }; | |
cc40b5ce | 432 | int res = drefs->refs->be->reflog_expire(drefs->refs, refname, |
34c31997 HWN |
433 | flags, &debug_reflog_expiry_prepare, |
434 | &debug_reflog_expiry_should_prune_fn, | |
435 | &debug_reflog_expiry_cleanup, | |
436 | &prune); | |
4441f427 HWN |
437 | trace_printf_key(&trace_refs, "reflog_expire: %s: %d\n", refname, res); |
438 | return res; | |
439 | } | |
440 | ||
441 | struct ref_storage_be refs_be_debug = { | |
32bff617 ÆAB |
442 | .next = NULL, |
443 | .name = "debug", | |
444 | .init = NULL, | |
445 | .init_db = debug_init_db, | |
5b875404 ÆAB |
446 | |
447 | /* | |
448 | * None of these should be NULL. If the "files" backend (in | |
449 | * "struct ref_storage_be refs_be_files" in files-backend.c) | |
450 | * has a function we should also have a wrapper for it here. | |
451 | * Test the output with "GIT_TRACE_REFS=1". | |
452 | */ | |
32bff617 ÆAB |
453 | .transaction_prepare = debug_transaction_prepare, |
454 | .transaction_finish = debug_transaction_finish, | |
455 | .transaction_abort = debug_transaction_abort, | |
456 | .initial_transaction_commit = debug_initial_transaction_commit, | |
457 | ||
458 | .pack_refs = debug_pack_refs, | |
459 | .create_symref = debug_create_symref, | |
460 | .delete_refs = debug_delete_refs, | |
461 | .rename_ref = debug_rename_ref, | |
462 | .copy_ref = debug_copy_ref, | |
463 | ||
464 | .iterator_begin = debug_ref_iterator_begin, | |
465 | .read_raw_ref = debug_read_raw_ref, | |
5b875404 | 466 | .read_symbolic_ref = debug_read_symbolic_ref, |
32bff617 ÆAB |
467 | |
468 | .reflog_iterator_begin = debug_reflog_iterator_begin, | |
469 | .for_each_reflog_ent = debug_for_each_reflog_ent, | |
470 | .for_each_reflog_ent_reverse = debug_for_each_reflog_ent_reverse, | |
471 | .reflog_exists = debug_reflog_exists, | |
472 | .create_reflog = debug_create_reflog, | |
473 | .delete_reflog = debug_delete_reflog, | |
474 | .reflog_expire = debug_reflog_expire, | |
4441f427 | 475 | }; |