Git fork

rerere: use strmap to store rerere directories

We store a struct for each directory we access under .git/rr-cache. The
structs are kept in an array sorted by the binary hash associated with
their name (and we do lookups with a binary search).

This works OK, but there are a few small downsides:

- the amount of code isn't huge, but it's more than we'd need using one
of our other stock data structures

- the insertion into a sorted array is quadratic (though in practice
it's unlikely anybody has enough conflicts for this to matter)

- it's intimately tied to the representation of an object hash. This
isn't a big deal, as the conflict ids we generate use the same hash,
but it produces a few awkward bits (e.g., we are the only user of
hash_pos() that is not using object_id).

Let's instead just treat the directory names as strings, and store them
in a strmap. This is less code, and removes the use of hash_pos().

Insertion is now non-quadratic, though we probably use a bit more
memory. Besides the hash table overhead, and storing hex bytes instead
of a binary hash, we actually store each name twice. Other code expects
to access the name of a rerere_dir struct from the struct itself, so we
need a copy there. But strmap keeps its own copy of the name, as well.

Using a bare hashmap instead of strmap means we could use the name for
both, but at the cost of extra code (e.g., our own comparison function).
Likewise, strmap has a feature to use a pointer to the in-struct name at
the cost of a little extra code. I didn't do either here, as simple code
seemed more important than squeezing out a few bytes of efficiency.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Jeff King and committed by
Junio C Hamano
680ff910 098c173f

+21 -37
+21 -37
rerere.c
··· 11 11 #include "pathspec.h" 12 12 #include "object-store.h" 13 13 #include "hash-lookup.h" 14 + #include "strmap.h" 14 15 15 16 #define RESOLVED 0 16 17 #define PUNTED 1 ··· 23 24 /* automatically update cleanly resolved paths to the index */ 24 25 static int rerere_autoupdate; 25 26 26 - static int rerere_dir_nr; 27 - static int rerere_dir_alloc; 28 - 29 27 #define RR_HAS_POSTIMAGE 1 30 28 #define RR_HAS_PREIMAGE 2 31 - static struct rerere_dir { 32 - unsigned char hash[GIT_MAX_HEXSZ]; 29 + struct rerere_dir { 33 30 int status_alloc, status_nr; 34 31 unsigned char *status; 35 - } **rerere_dir; 32 + char name[FLEX_ARRAY]; 33 + }; 34 + 35 + static struct strmap rerere_dirs = STRMAP_INIT; 36 36 37 37 static void free_rerere_dirs(void) 38 38 { 39 - int i; 40 - for (i = 0; i < rerere_dir_nr; i++) { 41 - free(rerere_dir[i]->status); 42 - free(rerere_dir[i]); 39 + struct hashmap_iter iter; 40 + struct strmap_entry *ent; 41 + 42 + strmap_for_each_entry(&rerere_dirs, &iter, ent) { 43 + struct rerere_dir *rr_dir = ent->value; 44 + free(rr_dir->status); 45 + free(rr_dir); 43 46 } 44 - FREE_AND_NULL(rerere_dir); 45 - rerere_dir_nr = rerere_dir_alloc = 0; 47 + strmap_clear(&rerere_dirs, 0); 46 48 } 47 49 48 50 static void free_rerere_id(struct string_list_item *item) ··· 52 54 53 55 static const char *rerere_id_hex(const struct rerere_id *id) 54 56 { 55 - return hash_to_hex(id->collection->hash); 57 + return id->collection->name; 56 58 } 57 59 58 60 static void fit_variant(struct rerere_dir *rr_dir, int variant) ··· 115 117 static void scan_rerere_dir(struct rerere_dir *rr_dir) 116 118 { 117 119 struct dirent *de; 118 - DIR *dir = opendir(git_path("rr-cache/%s", hash_to_hex(rr_dir->hash))); 120 + DIR *dir = opendir(git_path("rr-cache/%s", rr_dir->name)); 119 121 120 122 if (!dir) 121 123 return; ··· 133 135 closedir(dir); 134 136 } 135 137 136 - static const unsigned char *rerere_dir_hash(size_t i, void *table) 137 - { 138 - struct rerere_dir **rr_dir = table; 139 - return rr_dir[i]->hash; 140 - } 141 - 142 138 static struct rerere_dir *find_rerere_dir(const char *hex) 143 139 { 144 - unsigned char hash[GIT_MAX_RAWSZ]; 145 140 struct rerere_dir *rr_dir; 146 - int pos; 147 141 148 - if (get_sha1_hex(hex, hash)) 149 - BUG("cannot parse rerere dir hex?"); 150 - pos = hash_pos(hash, rerere_dir, rerere_dir_nr, rerere_dir_hash); 151 - if (pos < 0) { 152 - rr_dir = xmalloc(sizeof(*rr_dir)); 153 - hashcpy(rr_dir->hash, hash); 142 + rr_dir = strmap_get(&rerere_dirs, hex); 143 + if (!rr_dir) { 144 + FLEX_ALLOC_STR(rr_dir, name, hex); 154 145 rr_dir->status = NULL; 155 146 rr_dir->status_nr = 0; 156 147 rr_dir->status_alloc = 0; 157 - pos = -1 - pos; 148 + strmap_put(&rerere_dirs, hex, rr_dir); 158 149 159 - /* Make sure the array is big enough ... */ 160 - ALLOC_GROW(rerere_dir, rerere_dir_nr + 1, rerere_dir_alloc); 161 - /* ... and add it in. */ 162 - rerere_dir_nr++; 163 - MOVE_ARRAY(rerere_dir + pos + 1, rerere_dir + pos, 164 - rerere_dir_nr - pos - 1); 165 - rerere_dir[pos] = rr_dir; 166 150 scan_rerere_dir(rr_dir); 167 151 } 168 - return rerere_dir[pos]; 152 + return rr_dir; 169 153 } 170 154 171 155 static int has_rerere_resolution(const struct rerere_id *id)