Linus Torvalds | 3e4339e | 2006-06-18 11:45:02 -0700 | [diff] [blame] | 1 | #include "cache.h" |
| 2 | #include "object.h" |
Linus Torvalds | a59b276 | 2007-04-16 16:03:15 -0700 | [diff] [blame] | 3 | #include "decorate.h" |
Linus Torvalds | 3e4339e | 2006-06-18 11:45:02 -0700 | [diff] [blame] | 4 | |
| 5 | int track_object_refs = 0; |
| 6 | |
Linus Torvalds | a59b276 | 2007-04-16 16:03:15 -0700 | [diff] [blame] | 7 | static struct decoration ref_decorate; |
Linus Torvalds | 3e4339e | 2006-06-18 11:45:02 -0700 | [diff] [blame] | 8 | |
Linus Torvalds | a59b276 | 2007-04-16 16:03:15 -0700 | [diff] [blame] | 9 | struct object_refs *lookup_object_refs(struct object *base) |
Linus Torvalds | 3e4339e | 2006-06-18 11:45:02 -0700 | [diff] [blame] | 10 | { |
Linus Torvalds | a59b276 | 2007-04-16 16:03:15 -0700 | [diff] [blame] | 11 | return lookup_decoration(&ref_decorate, base); |
Linus Torvalds | 3e4339e | 2006-06-18 11:45:02 -0700 | [diff] [blame] | 12 | } |
| 13 | |
Linus Torvalds | a59b276 | 2007-04-16 16:03:15 -0700 | [diff] [blame] | 14 | static void add_object_refs(struct object *obj, struct object_refs *refs) |
Linus Torvalds | 5fdc849 | 2006-06-21 11:01:12 -0700 | [diff] [blame] | 15 | { |
Linus Torvalds | a59b276 | 2007-04-16 16:03:15 -0700 | [diff] [blame] | 16 | if (add_decoration(&ref_decorate, obj, refs)) |
| 17 | die("object %s tried to add refs twice!", sha1_to_hex(obj->sha1)); |
Linus Torvalds | 3e4339e | 2006-06-18 11:45:02 -0700 | [diff] [blame] | 18 | } |
| 19 | |
| 20 | struct object_refs *alloc_object_refs(unsigned count) |
| 21 | { |
| 22 | struct object_refs *refs; |
| 23 | size_t size = sizeof(*refs) + count*sizeof(struct object *); |
| 24 | |
| 25 | refs = xcalloc(1, size); |
| 26 | refs->count = count; |
| 27 | return refs; |
| 28 | } |
| 29 | |
| 30 | static int compare_object_pointers(const void *a, const void *b) |
| 31 | { |
| 32 | const struct object * const *pa = a; |
| 33 | const struct object * const *pb = b; |
| 34 | if (*pa == *pb) |
| 35 | return 0; |
| 36 | else if (*pa < *pb) |
| 37 | return -1; |
| 38 | else |
| 39 | return 1; |
| 40 | } |
| 41 | |
| 42 | void set_object_refs(struct object *obj, struct object_refs *refs) |
| 43 | { |
| 44 | unsigned int i, j; |
| 45 | |
| 46 | /* Do not install empty list of references */ |
| 47 | if (refs->count < 1) { |
| 48 | free(refs); |
| 49 | return; |
| 50 | } |
| 51 | |
| 52 | /* Sort the list and filter out duplicates */ |
| 53 | qsort(refs->ref, refs->count, sizeof(refs->ref[0]), |
| 54 | compare_object_pointers); |
| 55 | for (i = j = 1; i < refs->count; i++) { |
| 56 | if (refs->ref[i] != refs->ref[i - 1]) |
| 57 | refs->ref[j++] = refs->ref[i]; |
| 58 | } |
| 59 | if (j < refs->count) { |
| 60 | /* Duplicates were found - reallocate list */ |
| 61 | size_t size = sizeof(*refs) + j*sizeof(struct object *); |
| 62 | refs->count = j; |
| 63 | refs = xrealloc(refs, size); |
| 64 | } |
| 65 | |
| 66 | for (i = 0; i < refs->count; i++) |
| 67 | refs->ref[i]->used = 1; |
| 68 | add_object_refs(obj, refs); |
| 69 | } |
| 70 | |
| 71 | void mark_reachable(struct object *obj, unsigned int mask) |
| 72 | { |
| 73 | const struct object_refs *refs; |
| 74 | |
| 75 | if (!track_object_refs) |
| 76 | die("cannot do reachability with object refs turned off"); |
Linus Torvalds | 3e4339e | 2006-06-18 11:45:02 -0700 | [diff] [blame] | 77 | /* If we've been here already, don't bother */ |
| 78 | if (obj->flags & mask) |
| 79 | return; |
| 80 | obj->flags |= mask; |
| 81 | refs = lookup_object_refs(obj); |
| 82 | if (refs) { |
| 83 | unsigned i; |
| 84 | for (i = 0; i < refs->count; i++) |
| 85 | mark_reachable(refs->ref[i], mask); |
| 86 | } |
| 87 | } |