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