Skip to content

Commit

Permalink
name-hash.c: remove cache entries instead of marking them CE_UNHASHED
Browse files Browse the repository at this point in the history
The new hashmap implementation supports remove, so really remove unused
cache entries from the name hashmap instead of just marking them.

The CE_UNHASHED flag and CE_STATE_MASK are no longer needed.

Keep the CE_HASHED flag to prevent adding entries twice.

Signed-off-by: Karsten Blees <blees@dcon.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Karsten Blees authored and Junio C Hamano committed Nov 18, 2013
1 parent 8b01378 commit 419a597
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 30 deletions.
6 changes: 2 additions & 4 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ struct cache_entry {
#define CE_ADDED (1 << 19)

#define CE_HASHED (1 << 20)
#define CE_UNHASHED (1 << 21)
#define CE_WT_REMOVE (1 << 22) /* remove in work directory */
#define CE_CONFLICTED (1 << 23)

Expand Down Expand Up @@ -196,19 +195,18 @@ struct pathspec;
* Copy the sha1 and stat state of a cache entry from one to
* another. But we never change the name, or the hash state!
*/
#define CE_STATE_MASK (CE_HASHED | CE_UNHASHED)
static inline void copy_cache_entry(struct cache_entry *dst,
const struct cache_entry *src)
{
unsigned int state = dst->ce_flags & CE_STATE_MASK;
unsigned int state = dst->ce_flags & CE_HASHED;

/* Don't copy hash chain and name */
memcpy(&dst->ce_stat_data, &src->ce_stat_data,
offsetof(struct cache_entry, name) -
offsetof(struct cache_entry, ce_stat_data));

/* Restore the hash state */
dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
}

static inline unsigned create_ce_flags(unsigned stage)
Expand Down
46 changes: 22 additions & 24 deletions name-hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,29 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
hashmap_entry_init(ce, memihash(ce->name, ce_namelen(ce)));
hashmap_add(&istate->name_hash, ce);

if (ignore_case && !(ce->ce_flags & CE_UNHASHED))
if (ignore_case)
add_dir_entry(istate, ce);
}

static int cache_entry_cmp(const struct cache_entry *ce1,
const struct cache_entry *ce2, const void *remove)
{
/*
* For remove_name_hash, find the exact entry (pointer equality); for
* index_name_exists, find all entries with matching hash code and
* decide whether the entry matches in same_name.
*/
return remove ? !(ce1 == ce2) : 0;
}

static void lazy_init_name_hash(struct index_state *istate)
{
int nr;

if (istate->name_hash_initialized)
return;
hashmap_init(&istate->name_hash, NULL, istate->cache_nr);
hashmap_init(&istate->name_hash, (hashmap_cmp_fn) cache_entry_cmp,
istate->cache_nr);
hashmap_init(&istate->dir_hash, (hashmap_cmp_fn) dir_entry_cmp, 0);
for (nr = 0; nr < istate->cache_nr; nr++)
hash_index_entry(istate, istate->cache[nr]);
Expand All @@ -125,31 +137,19 @@ static void lazy_init_name_hash(struct index_state *istate)

void add_name_hash(struct index_state *istate, struct cache_entry *ce)
{
/* if already hashed, add reference to directory entries */
if (ignore_case && (ce->ce_flags & CE_STATE_MASK) == CE_STATE_MASK)
add_dir_entry(istate, ce);

ce->ce_flags &= ~CE_UNHASHED;
if (istate->name_hash_initialized)
hash_index_entry(istate, ce);
}

/*
* We don't actually *remove* it, we can just mark it invalid so that
* we won't find it in lookups.
*
* Not only would we have to search the lists (simple enough), but
* we'd also have to rehash other hash buckets in case this makes the
* hash bucket empty (common). So it's much better to just mark
* it.
*/
void remove_name_hash(struct index_state *istate, struct cache_entry *ce)
{
/* if already hashed, release reference to directory entries */
if (ignore_case && (ce->ce_flags & CE_STATE_MASK) == CE_HASHED)
remove_dir_entry(istate, ce);
if (!istate->name_hash_initialized || !(ce->ce_flags & CE_HASHED))
return;
ce->ce_flags &= ~CE_HASHED;
hashmap_remove(&istate->name_hash, ce, ce);

ce->ce_flags |= CE_UNHASHED;
if (ignore_case)
remove_dir_entry(istate, ce);
}

static int slow_same_name(const char *name1, int len1, const char *name2, int len2)
Expand Down Expand Up @@ -220,10 +220,8 @@ struct cache_entry *index_file_exists(struct index_state *istate, const char *na
hashmap_entry_init(&key, memihash(name, namelen));
ce = hashmap_get(&istate->name_hash, &key, NULL);
while (ce) {
if (!(ce->ce_flags & CE_UNHASHED)) {
if (same_name(ce, name, namelen, icase))
return ce;
}
if (same_name(ce, name, namelen, icase))
return ce;
ce = hashmap_get_next(&istate->name_hash, ce);
}
return NULL;
Expand Down
2 changes: 1 addition & 1 deletion read-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n

new = xmalloc(cache_entry_size(namelen));
copy_cache_entry(new, old);
new->ce_flags &= ~CE_STATE_MASK;
new->ce_flags &= ~CE_HASHED;
new->ce_namelen = namelen;
memcpy(new->name, new_name, namelen + 1);

Expand Down
2 changes: 1 addition & 1 deletion unpack-trees.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
unsigned int set, unsigned int clear)
{
clear |= CE_HASHED | CE_UNHASHED;
clear |= CE_HASHED;

if (set & CE_REMOVE)
set |= CE_WT_REMOVE;
Expand Down

0 comments on commit 419a597

Please sign in to comment.