@@ -50,6 +50,17 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,
50
50
*/
51
51
struct dir_entry * dir ;
52
52
unsigned int hash ;
53
+ int use_precomputed_dir_hash = 0 ;
54
+
55
+ if (ce -> precompute_hash_state & CE_PRECOMPUTE_HASH_STATE__SET ) {
56
+ if (!(ce -> precompute_hash_state & CE_PRECOMPUTE_HASH_STATE__DIR ))
57
+ return NULL ; /* item does not have a parent directory */
58
+ if (namelen == ce_namelen (ce )) {
59
+ /* dir hash only valid for outer-most call (not recursive ones) */
60
+ use_precomputed_dir_hash = 1 ;
61
+ hash = ce -> precompute_hash_dir ;
62
+ }
63
+ }
53
64
54
65
/* get length of parent directory */
55
66
while (namelen > 0 && !is_dir_sep (ce -> name [namelen - 1 ]))
@@ -59,7 +70,8 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,
59
70
namelen -- ;
60
71
61
72
/* lookup existing entry for that directory */
62
- hash = memihash (ce -> name , namelen );
73
+ if (!use_precomputed_dir_hash )
74
+ hash = memihash (ce -> name , namelen );
63
75
dir = find_dir_entry__hash (istate , ce -> name , namelen , hash );
64
76
if (!dir ) {
65
77
/* not found, create it and add to hash table */
@@ -99,10 +111,18 @@ static void remove_dir_entry(struct index_state *istate, struct cache_entry *ce)
99
111
100
112
static void hash_index_entry (struct index_state * istate , struct cache_entry * ce )
101
113
{
114
+ unsigned int h ;
115
+
102
116
if (ce -> ce_flags & CE_HASHED )
103
117
return ;
104
118
ce -> ce_flags |= CE_HASHED ;
105
- hashmap_entry_init (ce , memihash (ce -> name , ce_namelen (ce )));
119
+
120
+ if (ce -> precompute_hash_state & CE_PRECOMPUTE_HASH_STATE__SET )
121
+ h = ce -> precompute_hash_name ;
122
+ else
123
+ h = memihash (ce -> name , ce_namelen (ce ));
124
+
125
+ hashmap_entry_init (ce , h );
106
126
hashmap_add (& istate -> name_hash , ce );
107
127
108
128
if (ignore_case )
@@ -244,3 +264,45 @@ void free_name_hash(struct index_state *istate)
244
264
hashmap_free (& istate -> name_hash , 0 );
245
265
hashmap_free (& istate -> dir_hash , 1 );
246
266
}
267
+
268
+ /*
269
+ * Precompute the hash values for this cache_entry
270
+ * for use in the istate.name_hash and istate.dir_hash.
271
+ *
272
+ * If the item is in the root directory, just compute the
273
+ * hash value (for istate.name_hash) on the full path.
274
+ *
275
+ * If the item is in a subdirectory, first compute the
276
+ * hash value for the immediate parent directory (for
277
+ * istate.dir_hash) and then the hash value for the full
278
+ * path by continuing the computation.
279
+ *
280
+ * Note that these hashes will be used by
281
+ * wt_status_collect_untracked() as it scans the worktree
282
+ * and maps observed paths back to the index (optionally
283
+ * ignoring case). Therefore, we probably only *NEED* to
284
+ * precompute this for non-skip-worktree items (since
285
+ * status should not observe skipped items), but because
286
+ * lazy_init_name_hash() hashes everything, we force it
287
+ * here.
288
+ */
289
+ void precompute_istate_hashes (struct cache_entry * ce )
290
+ {
291
+ int namelen = ce_namelen (ce );
292
+
293
+ while (namelen > 0 && !is_dir_sep (ce -> name [namelen - 1 ]))
294
+ namelen -- ;
295
+
296
+ if (namelen <= 0 ) {
297
+ ce -> precompute_hash_name = memihash (ce -> name , ce_namelen (ce ));
298
+ ce -> precompute_hash_state = CE_PRECOMPUTE_HASH_STATE__SET ;
299
+ } else {
300
+ namelen -- ;
301
+ ce -> precompute_hash_dir = memihash (ce -> name , namelen );
302
+ ce -> precompute_hash_name = memihash_cont (
303
+ ce -> precompute_hash_dir , & ce -> name [namelen ],
304
+ ce_namelen (ce ) - namelen );
305
+ ce -> precompute_hash_state =
306
+ CE_PRECOMPUTE_HASH_STATE__SET | CE_PRECOMPUTE_HASH_STATE__DIR ;
307
+ }
308
+ }
0 commit comments