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