object-refs.con commit Merge branch 'jc/upload-corrupt' into next (78831b4)
   1#include "cache.h"
   2#include "object.h"
   3
   4int track_object_refs = 0;
   5
   6static unsigned int refs_hash_size, nr_object_refs;
   7static struct object_refs **refs_hash;
   8
   9static unsigned int hash_obj(struct object *obj, unsigned int n)
  10{
  11        unsigned int hash = *(unsigned int *)obj->sha1;
  12        return hash % n;
  13}
  14
  15static void grow_refs_hash(void)
  16{
  17        int i;
  18        int new_hash_size = (refs_hash_size + 1000) * 3 / 2;
  19        struct object_refs **new_hash;
  20
  21        new_hash = calloc(new_hash_size, sizeof(struct object_refs *));
  22        for (i = 0; i < refs_hash_size; i++) {
  23                int j;
  24                struct object_refs *ref = refs_hash[i];
  25                if (!ref)
  26                        continue;
  27                j = hash_obj(ref->base, new_hash_size);
  28                new_hash[j] = ref;
  29        }
  30        free(refs_hash);
  31        refs_hash = new_hash;
  32        refs_hash_size = new_hash_size;
  33}
  34
  35static void insert_ref_hash(struct object_refs *ref)
  36{
  37        int j = hash_obj(ref->base, refs_hash_size);
  38
  39        while (refs_hash[j]) {
  40                j++;
  41                if (j >= refs_hash_size)
  42                        j = 0;
  43        }
  44        refs_hash[j] = ref;
  45}
  46
  47static void add_object_refs(struct object *obj, struct object_refs *ref)
  48{
  49        int nr = nr_object_refs + 1;
  50
  51        if (nr > refs_hash_size * 2 / 3)
  52                grow_refs_hash();
  53        ref->base = obj;
  54        insert_ref_hash(ref);
  55        nr_object_refs = nr;
  56}
  57
  58struct object_refs *lookup_object_refs(struct object *obj)
  59{
  60        int j = hash_obj(obj, refs_hash_size);
  61        struct object_refs *ref;
  62
  63        while ((ref = refs_hash[j]) != NULL) {
  64                if (ref->base == obj)
  65                        break;
  66                j++;
  67                if (j >= refs_hash_size)
  68                        j = 0;
  69        }
  70        return ref;
  71}
  72
  73struct object_refs *alloc_object_refs(unsigned count)
  74{
  75        struct object_refs *refs;
  76        size_t size = sizeof(*refs) + count*sizeof(struct object *);
  77
  78        refs = xcalloc(1, size);
  79        refs->count = count;
  80        return refs;
  81}
  82
  83static int compare_object_pointers(const void *a, const void *b)
  84{
  85        const struct object * const *pa = a;
  86        const struct object * const *pb = b;
  87        if (*pa == *pb)
  88                return 0;
  89        else if (*pa < *pb)
  90                return -1;
  91        else
  92                return 1;
  93}
  94
  95void set_object_refs(struct object *obj, struct object_refs *refs)
  96{
  97        unsigned int i, j;
  98
  99        /* Do not install empty list of references */
 100        if (refs->count < 1) {
 101                free(refs);
 102                return;
 103        }
 104
 105        /* Sort the list and filter out duplicates */
 106        qsort(refs->ref, refs->count, sizeof(refs->ref[0]),
 107              compare_object_pointers);
 108        for (i = j = 1; i < refs->count; i++) {
 109                if (refs->ref[i] != refs->ref[i - 1])
 110                        refs->ref[j++] = refs->ref[i];
 111        }
 112        if (j < refs->count) {
 113                /* Duplicates were found - reallocate list */
 114                size_t size = sizeof(*refs) + j*sizeof(struct object *);
 115                refs->count = j;
 116                refs = xrealloc(refs, size);
 117        }
 118
 119        for (i = 0; i < refs->count; i++)
 120                refs->ref[i]->used = 1;
 121        add_object_refs(obj, refs);
 122}
 123
 124void mark_reachable(struct object *obj, unsigned int mask)
 125{
 126        const struct object_refs *refs;
 127
 128        if (!track_object_refs)
 129                die("cannot do reachability with object refs turned off");
 130        /* nothing to lookup */
 131        if (!refs_hash_size)
 132                return;
 133        /* If we've been here already, don't bother */
 134        if (obj->flags & mask)
 135                return;
 136        obj->flags |= mask;
 137        refs = lookup_object_refs(obj);
 138        if (refs) {
 139                unsigned i;
 140                for (i = 0; i < refs->count; i++)
 141                        mark_reachable(refs->ref[i], mask);
 142        }
 143}
 144
 145