@@ -23,17 +23,23 @@ static int dir_entry_cmp(const struct dir_entry *e1,
2323 name ? name : e2 -> name , e1 -> namelen );
2424}
2525
26- static struct dir_entry * find_dir_entry (struct index_state * istate ,
27- const char * name , unsigned int namelen )
26+ static struct dir_entry * find_dir_entry__hash (struct index_state * istate ,
27+ const char * name , unsigned int namelen , unsigned int hash )
2828{
2929 struct dir_entry key ;
30- hashmap_entry_init (& key , memihash ( name , namelen ) );
30+ hashmap_entry_init (& key , hash );
3131 key .namelen = namelen ;
3232 return hashmap_get (& istate -> dir_hash , & key , name );
3333}
3434
35+ static struct dir_entry * find_dir_entry (struct index_state * istate ,
36+ const char * name , unsigned int namelen )
37+ {
38+ return find_dir_entry__hash (istate , name , namelen , memihash (name ,namelen ));
39+ }
40+
3541static struct dir_entry * hash_dir_entry (struct index_state * istate ,
36- struct cache_entry * ce , int namelen )
42+ struct cache_entry * ce , int namelen , struct dir_entry * * p_previous_dir )
3743{
3844 /*
3945 * Throw each directory component in the hash for quick lookup
@@ -43,6 +49,18 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,
4349 * in index_state.name_hash (as ordinary cache_entries).
4450 */
4551 struct dir_entry * dir ;
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+ }
4664
4765 /* get length of parent directory */
4866 while (namelen > 0 && !is_dir_sep (ce -> name [namelen - 1 ]))
@@ -52,24 +70,43 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,
5270 namelen -- ;
5371
5472 /* lookup existing entry for that directory */
55- dir = find_dir_entry (istate , ce -> name , namelen );
73+ if (p_previous_dir && * p_previous_dir
74+ && namelen == (* p_previous_dir )-> namelen
75+ && memcmp (ce -> name , (* p_previous_dir )-> name , namelen ) == 0 ) {
76+ /*
77+ * When our caller is sequentially iterating thru the index,
78+ * items in the same directory will be sequential, and therefore
79+ * refer to the same dir_entry.
80+ */
81+ dir = * p_previous_dir ;
82+ } else {
83+ if (!use_precomputed_dir_hash )
84+ hash = memihash (ce -> name , namelen );
85+ dir = find_dir_entry__hash (istate , ce -> name , namelen , hash );
86+ }
87+
5688 if (!dir ) {
5789 /* not found, create it and add to hash table */
5890 FLEX_ALLOC_MEM (dir , name , ce -> name , namelen );
59- hashmap_entry_init (dir , memihash ( ce -> name , namelen ) );
91+ hashmap_entry_init (dir , hash );
6092 dir -> namelen = namelen ;
6193 hashmap_add (& istate -> dir_hash , dir );
6294
6395 /* recursively add missing parent directories */
64- dir -> parent = hash_dir_entry (istate , ce , namelen );
96+ dir -> parent = hash_dir_entry (istate , ce , namelen , NULL );
6597 }
98+
99+ if (p_previous_dir )
100+ * p_previous_dir = dir ;
101+
66102 return dir ;
67103}
68104
69- static void add_dir_entry (struct index_state * istate , struct cache_entry * ce )
105+ static void add_dir_entry (struct index_state * istate , struct cache_entry * ce ,
106+ struct dir_entry * * p_previous_dir )
70107{
71108 /* Add reference to the directory entry (and parents if 0). */
72- struct dir_entry * dir = hash_dir_entry (istate , ce , ce_namelen (ce ));
109+ struct dir_entry * dir = hash_dir_entry (istate , ce , ce_namelen (ce ), p_previous_dir );
73110 while (dir && !(dir -> nr ++ ))
74111 dir = dir -> parent ;
75112}
@@ -80,7 +117,7 @@ static void remove_dir_entry(struct index_state *istate, struct cache_entry *ce)
80117 * Release reference to the directory entry. If 0, remove and continue
81118 * with parent directory.
82119 */
83- struct dir_entry * dir = hash_dir_entry (istate , ce , ce_namelen (ce ));
120+ struct dir_entry * dir = hash_dir_entry (istate , ce , ce_namelen (ce ), NULL );
84121 while (dir && !(-- dir -> nr )) {
85122 struct dir_entry * parent = dir -> parent ;
86123 hashmap_remove (& istate -> dir_hash , dir , NULL );
@@ -89,16 +126,25 @@ static void remove_dir_entry(struct index_state *istate, struct cache_entry *ce)
89126 }
90127}
91128
92- static void hash_index_entry (struct index_state * istate , struct cache_entry * ce )
129+ static void hash_index_entry (struct index_state * istate , struct cache_entry * ce ,
130+ struct dir_entry * * p_previous_dir )
93131{
132+ unsigned int h ;
133+
94134 if (ce -> ce_flags & CE_HASHED )
95135 return ;
96136 ce -> ce_flags |= CE_HASHED ;
97- hashmap_entry_init (ce , memihash (ce -> name , ce_namelen (ce )));
137+
138+ if (ce -> precompute_hash_state & CE_PRECOMPUTE_HASH_STATE__SET )
139+ h = ce -> precompute_hash_name ;
140+ else
141+ h = memihash (ce -> name , ce_namelen (ce ));
142+
143+ hashmap_entry_init (ce , h );
98144 hashmap_add (& istate -> name_hash , ce );
99145
100146 if (ignore_case )
101- add_dir_entry (istate , ce );
147+ add_dir_entry (istate , ce , p_previous_dir );
102148}
103149
104150static int cache_entry_cmp (const struct cache_entry * ce1 ,
@@ -114,22 +160,24 @@ static int cache_entry_cmp(const struct cache_entry *ce1,
114160
115161static void lazy_init_name_hash (struct index_state * istate )
116162{
163+ struct dir_entry * previous_dir = NULL ;
117164 int nr ;
118165
119166 if (istate -> name_hash_initialized )
120167 return ;
121168 hashmap_init (& istate -> name_hash , (hashmap_cmp_fn ) cache_entry_cmp ,
122169 istate -> cache_nr );
123- hashmap_init (& istate -> dir_hash , (hashmap_cmp_fn ) dir_entry_cmp , 0 );
170+ hashmap_init (& istate -> dir_hash , (hashmap_cmp_fn ) dir_entry_cmp ,
171+ istate -> cache_nr );
124172 for (nr = 0 ; nr < istate -> cache_nr ; nr ++ )
125- hash_index_entry (istate , istate -> cache [nr ]);
173+ hash_index_entry (istate , istate -> cache [nr ], & previous_dir );
126174 istate -> name_hash_initialized = 1 ;
127175}
128176
129177void add_name_hash (struct index_state * istate , struct cache_entry * ce )
130178{
131179 if (istate -> name_hash_initialized )
132- hash_index_entry (istate , ce );
180+ hash_index_entry (istate , ce , NULL );
133181}
134182
135183void remove_name_hash (struct index_state * istate , struct cache_entry * ce )
@@ -236,3 +284,45 @@ void free_name_hash(struct index_state *istate)
236284 hashmap_free (& istate -> name_hash , 0 );
237285 hashmap_free (& istate -> dir_hash , 1 );
238286}
287+
288+ /*
289+ * Precompute the hash values for this cache_entry
290+ * for use in the istate.name_hash and istate.dir_hash.
291+ *
292+ * If the item is in the root directory, just compute the
293+ * hash value (for istate.name_hash) on the full path.
294+ *
295+ * If the item is in a subdirectory, first compute the
296+ * hash value for the immediate parent directory (for
297+ * istate.dir_hash) and then the hash value for the full
298+ * path by continuing the computation.
299+ *
300+ * Note that these hashes will be used by
301+ * wt_status_collect_untracked() as it scans the worktree
302+ * and maps observed paths back to the index (optionally
303+ * ignoring case). Therefore, we probably only *NEED* to
304+ * precompute this for non-skip-worktree items (since
305+ * status should not observe skipped items), but because
306+ * lazy_init_name_hash() hashes everything, we force it
307+ * here.
308+ */
309+ void precompute_istate_hashes (struct cache_entry * ce )
310+ {
311+ int namelen = ce_namelen (ce );
312+
313+ while (namelen > 0 && !is_dir_sep (ce -> name [namelen - 1 ]))
314+ namelen -- ;
315+
316+ if (namelen <= 0 ) {
317+ ce -> precompute_hash_name = memihash (ce -> name , ce_namelen (ce ));
318+ ce -> precompute_hash_state = CE_PRECOMPUTE_HASH_STATE__SET ;
319+ } else {
320+ namelen -- ;
321+ ce -> precompute_hash_dir = memihash (ce -> name , namelen );
322+ ce -> precompute_hash_name = memihash_cont (
323+ ce -> precompute_hash_dir , & ce -> name [namelen ],
324+ ce_namelen (ce ) - namelen );
325+ ce -> precompute_hash_state =
326+ CE_PRECOMPUTE_HASH_STATE__SET | CE_PRECOMPUTE_HASH_STATE__DIR ;
327+ }
328+ }
0 commit comments