hash: set, copy, and use algo field in struct object_id

Now that struct object_id has an algorithm field, we should populate it. This will allow us to handle object IDs in any supported algorithm and distinguish between them. Ensure that the field is written whenever we write an object ID by storing it explicitly every time we write an object. Set values for the empty blob and tree values as well. In addition, use the algorithm field to compare object IDs. Note that because we zero-initialize struct object_id in many places throughout the codebase, we default to the default algorithm in cases where the algorithm field is zero rather than explicitly initialize all of those locations. This leads to a branch on every comparison, but the alternative is to compare the entire buffer each time and padding the buffer for SHA-1. That alternative ranges up to 3.9% worse than this approach on the perf t0001, t1450, and t1451. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

brian m. carlson committed Apr 26, 2021 at 01:02 UTC 5a6dce70d7bb12ee2bc7926254c5b6741b91ac5f
4 files changed +54 -13
hash.h
+34 -6
@@ -192,36 +192,56 @@ static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
192
193 extern const struct object_id null_oid;
194
195 -static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
195 +static inline int hashcmp_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
196 {
197 /*
198 * Teach the compiler that there are only two possibilities of hash size
199 * here, so that it can optimize for this case as much as possible.
200 */
201 - if (the_hash_algo->rawsz == GIT_MAX_RAWSZ)
201 + if (algop->rawsz == GIT_MAX_RAWSZ)
202 return memcmp(sha1, sha2, GIT_MAX_RAWSZ);
203 return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
204 }
205
206 +static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
207 +{
208 + return hashcmp_algop(sha1, sha2, the_hash_algo);
209 +}
210 +
211 static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
212 {
208 - return hashcmp(oid1->hash, oid2->hash);
213 + const struct git_hash_algo *algop;
214 + if (!oid1->algo)
215 + algop = the_hash_algo;
216 + else
217 + algop = &hash_algos[oid1->algo];
218 + return hashcmp_algop(oid1->hash, oid2->hash, algop);
219 }
220
211 -static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)
221 +static inline int hasheq_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
222 {
223 /*
224 * We write this here instead of deferring to hashcmp so that the
225 * compiler can properly inline it and avoid calling memcmp.
226 */
217 - if (the_hash_algo->rawsz == GIT_MAX_RAWSZ)
227 + if (algop->rawsz == GIT_MAX_RAWSZ)
228 return !memcmp(sha1, sha2, GIT_MAX_RAWSZ);
229 return !memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
230 }
231
232 +static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)
233 +{
234 + return hasheq_algop(sha1, sha2, the_hash_algo);
235 +}
236 +
237 static inline int oideq(const struct object_id *oid1, const struct object_id *oid2)
238 {
224 - return hasheq(oid1->hash, oid2->hash);
239 + const struct git_hash_algo *algop;
240 + if (!oid1->algo)
241 + algop = the_hash_algo;
242 + else
243 + algop = &hash_algos[oid1->algo];
244 + return hasheq_algop(oid1->hash, oid2->hash, algop);
245 }
246
247 static inline int is_null_oid(const struct object_id *oid)
@@ -237,6 +257,7 @@ static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
257 static inline void oidcpy(struct object_id *dst, const struct object_id *src)
258 {
259 memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
260 + dst->algo = src->algo;
261 }
262
263 static inline struct object_id *oiddup(const struct object_id *src)
@@ -254,11 +275,13 @@ static inline void hashclr(unsigned char *hash)
275 static inline void oidclr(struct object_id *oid)
276 {
277 memset(oid->hash, 0, GIT_MAX_RAWSZ);
278 + oid->algo = hash_algo_by_ptr(the_hash_algo);
279 }
280
281 static inline void oidread(struct object_id *oid, const unsigned char *hash)
282 {
283 memcpy(oid->hash, hash, the_hash_algo->rawsz);
284 + oid->algo = hash_algo_by_ptr(the_hash_algo);
285 }
286
287 static inline int is_empty_blob_sha1(const unsigned char *sha1)
@@ -281,6 +304,11 @@ static inline int is_empty_tree_oid(const struct object_id *oid)
304 return oideq(oid, the_hash_algo->empty_tree);
305 }
306
307 +static inline void oid_set_algo(struct object_id *oid, const struct git_hash_algo *algop)
308 +{
309 + oid->algo = hash_algo_by_ptr(algop);
310 +}
311 +
312 const char *empty_tree_oid_hex(void);
313 const char *empty_blob_oid_hex(void);
314
hex.c
+6 -3
@@ -69,7 +69,10 @@ int get_sha1_hex(const char *hex, unsigned char *sha1)
69 int get_oid_hex_algop(const char *hex, struct object_id *oid,
70 const struct git_hash_algo *algop)
71 {
72 - return get_hash_hex_algop(hex, oid->hash, algop);
72 + int ret = get_hash_hex_algop(hex, oid->hash, algop);
73 + if (!ret)
74 + oid_set_algo(oid, algop);
75 + return ret;
76 }
77
78 /*
@@ -80,7 +83,7 @@ int get_oid_hex_any(const char *hex, struct object_id *oid)
83 {
84 int i;
85 for (i = GIT_HASH_NALGOS - 1; i > 0; i--) {
83 - if (!get_hash_hex_algop(hex, oid->hash, &hash_algos[i]))
86 + if (!get_oid_hex_algop(hex, oid, &hash_algos[i]))
87 return i;
88 }
89 return GIT_HASH_UNKNOWN;
@@ -95,7 +98,7 @@ int parse_oid_hex_algop(const char *hex, struct object_id *oid,
98 const char **end,
99 const struct git_hash_algo *algop)
100 {
98 - int ret = get_hash_hex_algop(hex, oid->hash, algop);
101 + int ret = get_oid_hex_algop(hex, oid, algop);
102 if (!ret)
103 *end = hex + algop->hexsz;
104 return ret;
notes.c
+3
@@ -455,6 +455,8 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
455 CALLOC_ARRAY(l, 1);
456 oidcpy(&l->key_oid, &object_oid);
457 oidcpy(&l->val_oid, &entry.oid);
458 + oid_set_algo(&l->key_oid, the_hash_algo);
459 + oid_set_algo(&l->val_oid, the_hash_algo);
460 if (note_tree_insert(t, node, n, l, type,
461 combine_notes_concatenate))
462 die("Failed to load %s %s into notes tree "
@@ -484,6 +486,7 @@ handle_non_note:
486 strbuf_addch(&non_note_path, '/');
487 }
488 strbuf_addstr(&non_note_path, entry.path);
489 + oid_set_algo(&entry.oid, the_hash_algo);
490 add_non_note(t, strbuf_detach(&non_note_path, NULL),
491 entry.mode, entry.oid.hash);
492 }
object-file.c
+11 -4
@@ -57,16 +57,20 @@
57
58 const struct object_id null_oid;
59 static const struct object_id empty_tree_oid = {
60 - EMPTY_TREE_SHA1_BIN_LITERAL
60 + .hash = EMPTY_TREE_SHA1_BIN_LITERAL,
61 + .algo = GIT_HASH_SHA1,
62 };
63 static const struct object_id empty_blob_oid = {
63 - EMPTY_BLOB_SHA1_BIN_LITERAL
64 + .hash = EMPTY_BLOB_SHA1_BIN_LITERAL,
65 + .algo = GIT_HASH_SHA1,
66 };
67 static const struct object_id empty_tree_oid_sha256 = {
66 - EMPTY_TREE_SHA256_BIN_LITERAL
68 + .hash = EMPTY_TREE_SHA256_BIN_LITERAL,
69 + .algo = GIT_HASH_SHA256,
70 };
71 static const struct object_id empty_blob_oid_sha256 = {
69 - EMPTY_BLOB_SHA256_BIN_LITERAL
72 + .hash = EMPTY_BLOB_SHA256_BIN_LITERAL,
73 + .algo = GIT_HASH_SHA256,
74 };
75
76 static void git_hash_sha1_init(git_hash_ctx *ctx)
@@ -93,6 +97,7 @@ static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx)
97 {
98 git_SHA1_Final(oid->hash, &ctx->sha1);
99 memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);
100 + oid->algo = GIT_HASH_SHA1;
101 }
102
103
@@ -124,6 +129,7 @@ static void git_hash_sha256_final_oid(struct object_id *oid, git_hash_ctx *ctx)
129 * but keep it in case we extend the hash size again.
130 */
131 memset(oid->hash + GIT_SHA256_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA256_RAWSZ);
132 + oid->algo = GIT_HASH_SHA256;
133 }
134
135 static void git_hash_unknown_init(git_hash_ctx *ctx)
@@ -2340,6 +2346,7 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
2346 if (namelen == the_hash_algo->hexsz - 2 &&
2347 !hex_to_bytes(oid.hash + 1, de->d_name,
2348 the_hash_algo->rawsz - 1)) {
2349 + oid_set_algo(&oid, the_hash_algo);
2350 if (obj_cb) {
2351 r = obj_cb(&oid, path->buf, data);
2352 if (r)