/* * Test performance of hashmap.[ch] * Usage: time echo "perfhashmap method rounds" | test-hashmap */ static void perf_hashmap(unsigned int method, unsigned int rounds) { struct hashmap map; char buf[16]; struct test_entry **entries; unsigned int *hashes; unsigned int i, j; entries = malloc(TEST_SIZE * sizeof(struct test_entry *)); hashes = malloc(TEST_SIZE * sizeof(int)); for (i = 0; i < TEST_SIZE; i++) { snprintf(buf, sizeof(buf), "%i", i); entries[i] = alloc_test_entry(0, buf, strlen(buf), "", 0); hashes[i] = hash(method, i, entries[i]->key); } if (method & TEST_ADD) { /* test adding to the map */ for (j = 0; j < rounds; j++) { hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp, 0); /* add entries */ for (i = 0; i < TEST_SIZE; i++) { hashmap_entry_init(entries[i], hashes[i]); hashmap_add(&map, entries[i]); } hashmap_free(&map, 0); } } else { /* test map lookups */ hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp, 0); /* fill the map (sparsely if specified) */ j = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE; for (i = 0; i < j; i++) { hashmap_entry_init(entries[i], hashes[i]); hashmap_add(&map, entries[i]); } for (j = 0; j < rounds; j++) { for (i = 0; i < TEST_SIZE; i++) { hashmap_get_from_hash(&map, hashes[i], entries[i]->key); } } hashmap_free(&map, 0); } }
static struct dir_entry *hash_dir_entry(struct index_state *istate, struct cache_entry *ce, int namelen) { /* * Throw each directory component in the hash for quick lookup * during a git status. Directory components are stored without their * closing slash. Despite submodules being a directory, they never * reach this point, because they are stored * in index_state.name_hash (as ordinary cache_entries). */ struct dir_entry *dir; /* get length of parent directory */ while (namelen > 0 && !is_dir_sep(ce->name[namelen - 1])) namelen--; if (namelen <= 0) return NULL; namelen--; /* lookup existing entry for that directory */ dir = find_dir_entry(istate, ce->name, namelen); if (!dir) { /* not found, create it and add to hash table */ FLEX_ALLOC_MEM(dir, name, ce->name, namelen); hashmap_entry_init(dir, memihash(ce->name, namelen)); dir->namelen = namelen; hashmap_add(&istate->dir_hash, dir); /* recursively add missing parent directories */ dir->parent = hash_dir_entry(istate, ce, namelen); } return dir; }
node *LVARglobaldef( node *arg_node, info *arg_info) { char *var_name; DBUG_ENTER("LVARglobaldef"); var_name = VAR_NAME(GLOBALDEF_ID( arg_node)); /* set declaration of this global variable */ VAR_DECL(GLOBALDEF_ID( arg_node) ) = arg_node; /* check for duplicated variable declaration */ if(hashmap_contains(arg_info->global, var_name)) { CTIerror(":%d: error: '%s' has already been defined in this context", NODE_LINE(arg_node), var_name); CTIerror(":%d: error: location of earlier definition", NODE_LINE((node *)hashmap_get(arg_info->global, var_name))); DBUG_RETURN(arg_node); } /* add global variabele declaration to hashmap */ hashmap_add(arg_info->global, var_name, arg_node); DBUG_RETURN( arg_node); }
/* * Adds a directory listing to the cache. */ static void fscache_add(struct fscache *cache, struct fsentry *fse) { if (fse->list) fse = fse->list; for (; fse; fse = fse->next) hashmap_add(&cache->map, fse); }
static void cache_add(struct submodule_cache *cache, struct submodule *submodule) { unsigned int hash = hash_sha1_string(submodule->gitmodules_sha1, submodule->name); struct submodule_entry *e = xmalloc(sizeof(*e)); hashmap_entry_init(e, hash); e->config = submodule; hashmap_add(&cache->for_name, e); }
static void hash_index_entry(struct index_state *istate, struct cache_entry *ce) { if (ce->ce_flags & CE_HASHED) return; ce->ce_flags |= CE_HASHED; hashmap_entry_init(ce, memihash(ce->name, ce_namelen(ce))); hashmap_add(&istate->name_hash, ce); if (ignore_case) add_dir_entry(istate, ce); }
static void changed_files(struct hashmap *result, const char *index_path, const char *workdir) { struct child_process update_index = CHILD_PROCESS_INIT; struct child_process diff_files = CHILD_PROCESS_INIT; struct strbuf index_env = STRBUF_INIT, buf = STRBUF_INIT; const char *git_dir = absolute_path(get_git_dir()), *env[] = { NULL, NULL }; FILE *fp; strbuf_addf(&index_env, "GIT_INDEX_FILE=%s", index_path); env[0] = index_env.buf; argv_array_pushl(&update_index.args, "--git-dir", git_dir, "--work-tree", workdir, "update-index", "--really-refresh", "-q", "--unmerged", NULL); update_index.no_stdin = 1; update_index.no_stdout = 1; update_index.no_stderr = 1; update_index.git_cmd = 1; update_index.use_shell = 0; update_index.clean_on_exit = 1; update_index.dir = workdir; update_index.env = env; /* Ignore any errors of update-index */ run_command(&update_index); argv_array_pushl(&diff_files.args, "--git-dir", git_dir, "--work-tree", workdir, "diff-files", "--name-only", "-z", NULL); diff_files.no_stdin = 1; diff_files.git_cmd = 1; diff_files.use_shell = 0; diff_files.clean_on_exit = 1; diff_files.out = -1; diff_files.dir = workdir; diff_files.env = env; if (start_command(&diff_files)) die("could not obtain raw diff"); fp = xfdopen(diff_files.out, "r"); while (!strbuf_getline_nul(&buf, fp)) { struct path_entry *entry; FLEX_ALLOC_STR(entry, path, buf.buf); hashmap_entry_init(entry, strhash(buf.buf)); hashmap_add(result, entry); } fclose(fp); if (finish_command(&diff_files)) die("diff-files did not exit properly"); strbuf_release(&index_env); strbuf_release(&buf); }
void _isvn_commitdrain_add(unsigned rev, int incr) { struct fetchdone_range *newr, *exist, key; key.r_lo = rev; hashmap_entry_init(&key.r_entry, memhash(&key.r_lo, sizeof(key.r_lo))); if (incr > 0) { newr = xmalloc(sizeof(*newr)); newr->r_lo = rev; newr->r_hi = incr; /* reused as refcnt */ hashmap_entry_init(&newr->r_entry, memhash(&newr->r_lo, sizeof(newr->r_lo))); } else newr = NULL; isvn_g_lock(); exist = hashmap_get(&g_commitdrain_hash, &key); if (incr > 0) { if (exist) exist->r_hi += incr; else hashmap_add(&g_commitdrain_hash, newr); } else { int refcnt; /* INVARIANTS */ if (exist == NULL) die("negative refcnt %d (ne)", incr); refcnt = (int)exist->r_hi + incr; /* INVARIANTS */ if (refcnt < 0) die("negative refcnt %d", refcnt); if (refcnt > 0) exist->r_hi = refcnt; else { hashmap_remove(&g_commitdrain_hash, exist); /* free it below */ newr = exist; } } isvn_g_unlock(); if (exist && newr) free(newr); }
static void *lazy_name_thread_proc(void *_data) { struct lazy_name_thread_data *d = _data; int k; for (k = 0; k < d->istate->cache_nr; k++) { struct cache_entry *ce_k = d->istate->cache[k]; ce_k->ce_flags |= CE_HASHED; hashmap_entry_init(ce_k, d->lazy_entries[k].hash_name); hashmap_add(&d->istate->name_hash, ce_k); } return NULL; }
struct patch_id *add_commit_patch_id(struct commit *commit, struct patch_ids *ids) { struct patch_id *key = xcalloc(1, sizeof(*key)); if (!patch_id_defined(commit)) return NULL; if (init_patch_id_entry(key, commit, ids)) { free(key); return NULL; } hashmap_add(&ids->patches, key); return key; }
static struct dir_entry *hash_dir_entry_with_parent_and_prefix( struct index_state *istate, struct dir_entry *parent, struct strbuf *prefix) { struct dir_entry *dir; unsigned int hash; int lock_nr; /* * Either we have a parent directory and path with slash(es) * or the directory is an immediate child of the root directory. */ assert((parent != NULL) ^ (strchr(prefix->buf, '/') == NULL)); if (parent) hash = memihash_cont(parent->ent.hash, prefix->buf + parent->namelen, prefix->len - parent->namelen); else hash = memihash(prefix->buf, prefix->len); lock_nr = compute_dir_lock_nr(&istate->dir_hash, hash); lock_dir_mutex(lock_nr); dir = find_dir_entry__hash(istate, prefix->buf, prefix->len, hash); if (!dir) { FLEX_ALLOC_MEM(dir, name, prefix->buf, prefix->len); hashmap_entry_init(dir, hash); dir->namelen = prefix->len; dir->parent = parent; hashmap_add(&istate->dir_hash, dir); if (parent) { unlock_dir_mutex(lock_nr); /* All I really need here is an InterlockedIncrement(&(parent->nr)) */ lock_nr = compute_dir_lock_nr(&istate->dir_hash, parent->ent.hash); lock_dir_mutex(lock_nr); parent->nr++; } } unlock_dir_mutex(lock_nr); return dir; }
void fscache_merge(struct fscache *dest) { struct hashmap_iter iter; struct hashmap_entry *e; struct fscache *cache = fscache_getcache(); /* * Only do the merge if fscache was enabled and we have a dest * cache to merge into. */ if (!dest) { fscache_enable(0); return; } if (!cache) BUG("fscache_merge() called on a thread where fscache has not been initialized"); TlsSetValue(dwTlsIndex, NULL); trace_printf_key(&trace_fscache, "fscache_merge: lstat %u, opendir %u, " "total requests/misses %u/%u\n", cache->lstat_requests, cache->opendir_requests, cache->fscache_requests, cache->fscache_misses); /* * This is only safe because the primary thread we're merging into * isn't being used so the critical section only needs to prevent * the the child threads from stomping on each other. */ EnterCriticalSection(&fscache_cs); hashmap_iter_init(&cache->map, &iter); while ((e = hashmap_iter_next(&iter))) hashmap_add(&dest->map, e); mem_pool_combine(dest->mem_pool, cache->mem_pool); dest->lstat_requests += cache->lstat_requests; dest->opendir_requests += cache->opendir_requests; dest->fscache_requests += cache->fscache_requests; dest->fscache_misses += cache->fscache_misses; initialized--; LeaveCriticalSection(&fscache_cs); free(cache); }
/* Add 'value' to a hashmap based on the provided 'key'. */ static void attr_hashmap_add(struct attr_hashmap *map, const char *key, size_t keylen, void *value) { struct attr_hash_entry *e; if (!map->map.tablesize) attr_hashmap_init(map); e = xmalloc(sizeof(struct attr_hash_entry)); hashmap_entry_init(e, memhash(key, keylen)); e->key = key; e->keylen = keylen; e->value = value; hashmap_add(&map->map, e); }
static void add_left_or_right(struct hashmap *map, const char *path, const char *content, int is_right) { struct pair_entry *e, *existing; FLEX_ALLOC_STR(e, path, path); hashmap_entry_init(e, strhash(path)); existing = hashmap_get(map, e, NULL); if (existing) { free(e); e = existing; } else { e->left[0] = e->right[0] = '\0'; hashmap_add(map, e); } strlcpy(is_right ? e->right : e->left, content, PATH_MAX); }
void isvn_mark_fetchdone(unsigned revlo, unsigned revhi) { struct fetchdone_range *done, *exist, key; done = xmalloc(sizeof(*done)); if (done == NULL) die("malloc"); isvn_g_lock(); if (g_rev_fetchdone == revlo - 1) { g_rev_fetchdone = revhi; while (true) { key.r_lo = revhi + 1; hashmap_entry_init(&key.r_entry, memhash(&key.r_lo, sizeof(key.r_lo))); exist = hashmap_remove(&g_fetchdone_hash, &key); if (!exist) break; g_rev_fetchdone = revhi = exist->r_hi; free(exist); } cond_broadcast(&g_rev_cond); } else { done->r_lo = revlo; done->r_hi = revhi; hashmap_entry_init(&done->r_entry, memhash(&done->r_lo, sizeof(done->r_lo))); hashmap_add(&g_fetchdone_hash, done); done = NULL; } isvn_g_unlock(); if (done) free(done); }
static void find_exact_matches(struct string_list *a, struct string_list *b) { struct hashmap map; int i; hashmap_init(&map, (hashmap_cmp_fn)patch_util_cmp, NULL, 0); /* First, add the patches of a to a hash map */ for (i = 0; i < a->nr; i++) { struct patch_util *util = a->items[i].util; util->i = i; util->patch = a->items[i].string; util->diff = util->patch + util->diff_offset; hashmap_entry_init(util, strhash(util->diff)); hashmap_add(&map, util); } /* Now try to find exact matches in b */ for (i = 0; i < b->nr; i++) { struct patch_util *util = b->items[i].util, *other; util->i = i; util->patch = b->items[i].string; util->diff = util->patch + util->diff_offset; hashmap_entry_init(util, strhash(util->diff)); other = hashmap_remove(&map, util, NULL); if (other) { if (other->matching >= 0) BUG("already assigned!"); other->matching = i; util->matching = other->i; } } hashmap_free(&map, 0); }
static void add_to_known_names(const char *path, const unsigned char *peeled, int prio, const unsigned char *sha1) { struct commit_name *e = find_commit_name(peeled); struct tag *tag = NULL; if (replace_name(e, prio, sha1, &tag)) { if (!e) { e = xmalloc(sizeof(struct commit_name)); hashcpy(e->peeled, peeled); hashmap_entry_init(e, sha1hash(peeled)); hashmap_add(&names, e); e->path = NULL; } e->tag = tag; e->prio = prio; e->name_checked = 0; hashcpy(e->sha1, sha1); free(e->path); e->path = xstrdup(path); } }
int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd, subprocess_start_fn startfn) { int err; struct child_process *process; const char *argv[] = { cmd, NULL }; entry->cmd = cmd; process = &entry->process; child_process_init(process); process->argv = argv; process->use_shell = 1; process->in = -1; process->out = -1; process->clean_on_exit = 1; process->clean_on_exit_handler = subprocess_exit_handler; err = start_command(process); if (err) { error("cannot fork to run subprocess '%s'", cmd); return err; } hashmap_entry_init(entry, strhash(cmd)); err = startfn(entry); if (err) { error("initialization for subprocess '%s' failed", cmd); subprocess_stop(hashmap, entry); return err; } hashmap_add(hashmap, entry); return 0; }
void hashmap_test(void) { printf("hashmap: running tests..."); Hashmap *map_1; map_1 = hashmap_create(100, NULL, &hashmap_hash_cstring, &hashmap_compare_cstring); hashmap_add(map_1, "pickles", (void*)pickle_value); assert( hashmap_count(map_1) == 1 ); assert( hashmap_contains(map_1, "apricots") == HASHMAP_NOT_FOUND ); assert( hashmap_contains(map_1, "pickles") == HASHMAP_FOUND ); assert( hashmap_item(map_1, "apricots") == NULL ); assert( hashmap_item(map_1, "pickles") == pickle_value ); hashmap_add(map_1, "pickles", (void*)pickle_value); assert( hashmap_count(map_1) == 1 ); hashmap_add(map_1, "apples", (void*)apple_value); assert( hashmap_count(map_1) == 2 ); assert( hashmap_contains(map_1, "apricots") == HASHMAP_NOT_FOUND ); assert( hashmap_contains(map_1, "pickles") == HASHMAP_FOUND ); assert( hashmap_contains(map_1, "apples") == HASHMAP_FOUND ); assert( hashmap_item(map_1, "apricots") == NULL ); assert( hashmap_item(map_1, "pickles") == pickle_value ); assert( hashmap_item(map_1, "apples") == apple_value ); hashmap_add(map_1, "pizza", (void*)pizza_value); assert( hashmap_count(map_1) == 3 ); assert( hashmap_contains(map_1, "apricots") == HASHMAP_NOT_FOUND ); assert( hashmap_contains(map_1, "pickles") == HASHMAP_FOUND ); assert( hashmap_contains(map_1, "apples") == HASHMAP_FOUND ); assert( hashmap_contains(map_1, "pizza") == HASHMAP_FOUND ); assert( hashmap_item(map_1, "apricots") == NULL ); assert( hashmap_item(map_1, "pickles") == pickle_value ); assert( hashmap_item(map_1, "apples") == apple_value ); assert( hashmap_item(map_1, "pizza") == pizza_value ); assert(map_1->buckets[28].pair_count == 1); assert(map_1->buckets[66].pair_count == 1); assert(map_1->buckets[51].pair_count == 1); assert(map_1->buckets[10].pair_count == 0); hashmap_enumerate(map_1, test_enumerator_); hashmap_remove(map_1, "apples"); assert( hashmap_count(map_1) == 2 ); assert( hashmap_contains(map_1, "apricots") == HASHMAP_NOT_FOUND ); assert( hashmap_contains(map_1, "pickles") == HASHMAP_FOUND ); assert( hashmap_contains(map_1, "apples") == HASHMAP_NOT_FOUND ); assert( hashmap_contains(map_1, "pizza") == HASHMAP_FOUND ); assert( hashmap_item(map_1, "apricots") == NULL ); assert( hashmap_item(map_1, "pickles") == pickle_value ); assert( hashmap_item(map_1, "apples") == NULL ); assert( hashmap_item(map_1, "pizza") == pizza_value ); hashmap_clear(map_1); assert( hashmap_count(map_1) == 0 ); hashmap_dispose(map_1); assert( (unsigned long)hashmap_hash_cstring(NULL, "pickles") % 100 == 28 ); assert( (unsigned long)hashmap_hash_cstring(NULL, "apples") % 100 == 66 ); assert( (unsigned long)hashmap_hash_cstring(NULL, "pizza") % 100 == 51 ); assert( (unsigned long)hashmap_hash_cstring(NULL, "apricots") % 100 == 10 ); map_1 = hashmap_create(1, NULL, &hashmap_hash_cstring, &hashmap_compare_cstring); hashmap_add(map_1, "pickles", (void*)pickle_value); assert( hashmap_count(map_1) == 1 ); hashmap_add(map_1, "pizza", (void*)pizza_value); assert( hashmap_count(map_1) == 2 ); hashmap_add(map_1, "apples", (void*)apple_value); assert( hashmap_count(map_1) == 3 ); assert( hashmap_contains(map_1, "apricots") == HASHMAP_NOT_FOUND ); assert( hashmap_contains(map_1, "pickles") == HASHMAP_FOUND ); assert( hashmap_contains(map_1, "apples") == HASHMAP_FOUND ); assert( hashmap_contains(map_1, "pizza") == HASHMAP_FOUND ); assert( hashmap_item(map_1, "apricots") == NULL ); assert( hashmap_item(map_1, "pickles") == pickle_value ); assert( hashmap_item(map_1, "apples") == apple_value ); assert( hashmap_item(map_1, "pizza") == pizza_value ); assert(map_1->buckets[0].pair_count == 3); hashmap_add(map_1, "pizza", (void*)apple_value); assert( hashmap_count(map_1) == 3 ); assert( hashmap_contains(map_1, "apricots") == HASHMAP_NOT_FOUND ); assert( hashmap_contains(map_1, "pickles") == HASHMAP_FOUND ); assert( hashmap_contains(map_1, "apples") == HASHMAP_FOUND ); assert( hashmap_contains(map_1, "pizza") == HASHMAP_FOUND ); assert( hashmap_item(map_1, "apricots") == NULL ); assert( hashmap_item(map_1, "pickles") == pickle_value ); assert( hashmap_item(map_1, "apples") == apple_value ); assert( hashmap_item(map_1, "pizza") == apple_value ); assert(strcmp(map_1->buckets[0].pairs[0]->key, "apples") == 0); assert(strcmp(map_1->buckets[0].pairs[1]->key, "pickles") == 0); assert(strcmp(map_1->buckets[0].pairs[2]->key, "pizza") == 0); hashmap_dispose(map_1); printf("ok.\n"); }
/* * Looks up or creates a cache entry for the specified key. */ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key) { struct fsentry *fse; int dir_not_found; cache->fscache_requests++; /* check if entry is in cache */ fse = hashmap_get(&cache->map, key, NULL); if (fse) { if (fse->st_mode) fsentry_addref(fse); else fse = NULL; /* non-existing directory */ return fse; } /* if looking for a file, check if directory listing is in cache */ if (!fse && key->list) { fse = hashmap_get(&cache->map, key->list, NULL); if (fse) { /* * dir entry without file entry, or dir does not * exist -> file doesn't exist */ errno = ENOENT; return NULL; } } /* create the directory listing */ fse = fsentry_create_list(cache, key->list ? key->list : key, &dir_not_found); /* leave on error (errno set by fsentry_create_list) */ if (!fse) { if (dir_not_found && key->list) { /* * Record that the directory does not exist (or is * empty, which for all practical matters is the same * thing as far as fscache is concerned). */ fse = fsentry_alloc(cache, key->list->list, key->list->name, key->list->len); fse->st_mode = 0; hashmap_add(&cache->map, fse); } return NULL; } /* add directory listing to the cache */ cache->fscache_misses++; fscache_add(cache, fse); /* lookup file entry if requested (fse already points to directory) */ if (key->list) fse = hashmap_get(&cache->map, key, NULL); if (fse && !fse->st_mode) fse = NULL; /* non-existing directory */ /* return entry or ENOENT */ if (fse) fsentry_addref(fse); else errno = ENOENT; return fse; }
int fatfs_vfs_lookup( struct file_node *node, struct file_node *buf, char *name, int flags ){ int ret = -ERROR_NOT_FOUND; fatfs_device_t *dev = node->fs->devstruct; unsigned cluster_size; //char namebuf[256]; char *namebuf; uint8_t *sectbuf; int i; int has_longname = 0; fatfs_dirent_t *dirbuf; fatfs_dircache_t *dircache; fatfs_dircache_t *newcache; fatfs_longname_ent_t *longentbuf; dircache = hashmap_get( dev->inode_map, node->inode ); if ( dircache ){ namebuf = knew( char[ 256 ]); if ( dircache->dir.attributes & FAT_ATTR_DIRECTORY ){ cluster_size = dev->bpb->bytes_per_sect * dev->bpb->sect_per_clus; sectbuf = knew( uint8_t[cluster_size] ); dirbuf = (void *)sectbuf; VFS_FUNCTION(( &dev->device_node ), read, sectbuf, cluster_size, dev->bpb->bytes_per_sect * node->inode ); for ( i = 0; i < dev->bpb->dirents; i++ ){ if ( *(char *)(dirbuf + i) == 0 || *(char *)(dirbuf + i) == 0xe5 ) continue; if ( dirbuf[i].attributes == FAT_ATTR_LONGNAME ){ longentbuf = (void *)(dirbuf + i); fatfs_apply_longname( longentbuf, namebuf, 256 ); has_longname = 1; } else { char *fname = has_longname? namebuf : (char *)dirbuf[i].name; if ( strcmp( name, fname ) == 0 ){ // Found it, cool newcache = knew( fatfs_dircache_t ); memcpy( &newcache->dir, dirbuf + i, sizeof( fatfs_dirent_t )); newcache->references = 0; buf->inode = fatfs_relclus_to_sect( dev, newcache->dir.cluster_low ); buf->fs = node->fs; buf->mount = 0; if ( hashmap_get( dev->inode_map, buf->inode ) == 0 ) hashmap_add( dev->inode_map, buf->inode, newcache ); ret = 0; break; } has_longname = 0; namebuf[0] = 0; } } kfree( sectbuf ); } else { ret = -ERROR_NOT_DIRECTORY; } kfree( namebuf ); } else {
void myHashMapPut(MyHashMap*obj, int key, int value){ hashmap_add(hm, key, value); }
void isvn_mark_commitdone(unsigned revlo, unsigned revhi) { struct fetchdone_range *done, *exist, key; struct fetchdone_range *drainex, drainkey; /* In particular, checking for refs in need of draining ... for each * rev in range. */ if (revlo != revhi) die("XXX batched commitdones notimpl."); done = xmalloc(sizeof(*done)); drainkey.r_lo = revlo; hashmap_entry_init(&drainkey.r_entry, memhash(&drainkey.r_lo, sizeof(drainkey.r_lo))); isvn_g_lock(); /* For revs with multiple branch edits (rare), wait until all commits * are in before marking done. */ drainex = hashmap_get(&g_commitdrain_hash, &drainkey); if (drainex) { drainex->r_hi--; if (drainex->r_hi == 0) { hashmap_remove(&g_commitdrain_hash, drainex); free(drainex); } else goto out; } if (g_rev_commitdone == revlo - 1) { g_rev_commitdone = revhi; while (true) { key.r_lo = revhi + 1; hashmap_entry_init(&key.r_entry, memhash(&key.r_lo, sizeof(key.r_lo))); exist = hashmap_remove(&g_commitdone_hash, &key); if (!exist) break; g_rev_commitdone = revhi = exist->r_hi; free(exist); } cond_broadcast(&g_commitdone_cond); } else { done->r_lo = revlo; done->r_hi = revhi; hashmap_entry_init(&done->r_entry, memhash(&done->r_lo, sizeof(done->r_lo))); hashmap_add(&g_commitdone_hash, done); done = NULL; } out: isvn_g_unlock(); if (done) free(done); }
/* * Read stdin line by line and print result of commands to stdout: * * hash key -> strhash(key) memhash(key) strihash(key) memihash(key) * put key value -> NULL / old value * get key -> NULL / value * remove key -> NULL / old value * iterate -> key1 value1\nkey2 value2\n... * size -> tablesize numentries * * perfhashmap method rounds -> test hashmap.[ch] performance */ int main(int argc, char *argv[]) { char line[1024]; struct hashmap map; int icase; /* init hash map */ icase = argc > 1 && !strcmp("ignorecase", argv[1]); hashmap_init(&map, (hashmap_cmp_fn) (icase ? test_entry_cmp_icase : test_entry_cmp), 0); /* process commands from stdin */ while (fgets(line, sizeof(line), stdin)) { char *cmd, *p1 = NULL, *p2 = NULL; int l1 = 0, l2 = 0, hash = 0; struct test_entry *entry; /* break line into command and up to two parameters */ cmd = strtok(line, DELIM); /* ignore empty lines */ if (!cmd || *cmd == '#') continue; p1 = strtok(NULL, DELIM); if (p1) { l1 = strlen(p1); hash = icase ? strihash(p1) : strhash(p1); p2 = strtok(NULL, DELIM); if (p2) l2 = strlen(p2); } if (!strcmp("hash", cmd) && l1) { /* print results of different hash functions */ printf("%u %u %u %u\n", strhash(p1), memhash(p1, l1), strihash(p1), memihash(p1, l1)); } else if (!strcmp("add", cmd) && l1 && l2) { /* create entry with key = p1, value = p2 */ entry = alloc_test_entry(hash, p1, l1, p2, l2); /* add to hashmap */ hashmap_add(&map, entry); } else if (!strcmp("put", cmd) && l1 && l2) { /* create entry with key = p1, value = p2 */ entry = alloc_test_entry(hash, p1, l1, p2, l2); /* add / replace entry */ entry = hashmap_put(&map, entry); /* print and free replaced entry, if any */ puts(entry ? get_value(entry) : "NULL"); free(entry); } else if (!strcmp("get", cmd) && l1) { /* lookup entry in hashmap */ entry = hashmap_get_from_hash(&map, hash, p1); /* print result */ if (!entry) puts("NULL"); while (entry) { puts(get_value(entry)); entry = hashmap_get_next(&map, entry); } } else if (!strcmp("remove", cmd) && l1) { /* setup static key */ struct hashmap_entry key; hashmap_entry_init(&key, hash); /* remove entry from hashmap */ entry = hashmap_remove(&map, &key, p1); /* print result and free entry*/ puts(entry ? get_value(entry) : "NULL"); free(entry); } else if (!strcmp("iterate", cmd)) { struct hashmap_iter iter; hashmap_iter_init(&map, &iter); while ((entry = hashmap_iter_next(&iter))) printf("%s %s\n", entry->key, get_value(entry)); } else if (!strcmp("size", cmd)) { /* print table sizes */ printf("%u %u\n", map.tablesize, map.size); } else if (!strcmp("intern", cmd) && l1) { /* test that strintern works */ const char *i1 = strintern(p1); const char *i2 = strintern(p1); if (strcmp(i1, p1)) printf("strintern(%s) returns %s\n", p1, i1); else if (i1 == p1) printf("strintern(%s) returns input pointer\n", p1); else if (i1 != i2) printf("strintern(%s) != strintern(%s)", i1, i2); else printf("%s\n", i1); } else if (!strcmp("perfhashmap", cmd) && l1 && l2) { perf_hashmap(atoi(p1), atoi(p2)); } else { printf("Unknown command %s\n", cmd); } } hashmap_free(&map, 1); return 0; }
/* * Looks up or creates a cache entry for the specified key. */ static struct fsentry *fscache_get(struct fsentry *key) { struct fsentry *fse, *future, *waiter; int dir_not_found; EnterCriticalSection(&mutex); /* check if entry is in cache */ fse = fscache_get_wait(key); if (fse) { if (fse->st_mode) fsentry_addref(fse); else fse = NULL; /* non-existing directory */ LeaveCriticalSection(&mutex); return fse; } /* if looking for a file, check if directory listing is in cache */ if (!fse && key->list) { fse = fscache_get_wait(key->list); if (fse) { LeaveCriticalSection(&mutex); /* * dir entry without file entry, or dir does not * exist -> file doesn't exist */ errno = ENOENT; return NULL; } } /* add future entry to indicate that we're loading it */ future = key->list ? key->list : key; future->next = NULL; future->refcnt = 0; hashmap_add(&map, future); /* create the directory listing (outside mutex!) */ LeaveCriticalSection(&mutex); fse = fsentry_create_list(future, &dir_not_found); EnterCriticalSection(&mutex); /* remove future entry and signal waiting threads */ hashmap_remove(&map, future, NULL); waiter = future->next; while (waiter) { HANDLE h = waiter->hwait; waiter = waiter->next; SetEvent(h); } /* leave on error (errno set by fsentry_create_list) */ if (!fse) { if (dir_not_found && key->list) { /* * Record that the directory does not exist (or is * empty, which for all practical matters is the same * thing as far as fscache is concerned). */ fse = fsentry_alloc(key->list->list, key->list->name, key->list->len); fse->st_mode = 0; hashmap_add(&map, fse); } LeaveCriticalSection(&mutex); return NULL; } /* add directory listing to the cache */ fscache_add(fse); /* lookup file entry if requested (fse already points to directory) */ if (key->list) fse = hashmap_get(&map, key, NULL); if (fse && !fse->st_mode) fse = NULL; /* non-existing directory */ /* return entry or ENOENT */ if (fse) fsentry_addref(fse); else errno = ENOENT; LeaveCriticalSection(&mutex); return fse; }
static void testmap(unsigned n, unsigned m, unsigned of, unsigned fp) { unsigned *knownkeys = malloc(sizeof (unsigned) * (m + of)); unsigned *mapkeys = malloc(sizeof (unsigned) * (m + of)); char *mapvals = malloc(sizeof (char *) * (m + of)); unsigned i, j, k; int err; memset(knownkeys, 0, sizeof (unsigned) * (m + of)); memset(mapkeys, 0, sizeof (unsigned) * (m + of)); memset(mapvals, 0, sizeof (char *) * (m + of)); timebase_init(&timebase); printf("adding %d\n", n); tacc = 0; tcnt = 0; for (i = 0; i < n + of; ++i) { add_again: k = rand() % 0xffff; for (j = 0; j < i; ++j) if (k == knownkeys[j]) goto add_again; knownkeys[i] = k; tick = timebase_count(); if ((err = hashmap_add(mapkeys, m, k)) < 0) { fprintf(stderr, "hashmap_add failed: i=%d/%d k=%04x\n", i, n, k); exit(1); } tock = timebase_count(); tacc += tock - tick; ++tcnt; } printf(" => %lums [%lu]\n", timebase_msec(&timebase, tacc), tcnt); printf("finding %d\n", n); tacc = 0; tcnt = 0; for (i = 0; i < n; ++i) { k = knownkeys[i]; tick = timebase_count(); if (hashmap_find(mapkeys, m, k) < 0) { fprintf(stderr, "hashmap_find failed: i=%d/%d k=%04x\n", i, n, k); exit(1); } tock = timebase_count(); tacc += tock - tick; ++tcnt; } printf(" => %lums [%lu]\n", timebase_msec(&timebase, tacc), tcnt); printf("finding %d invalid\n", fp); tacc = 0; tcnt = 0; k = 0x1337; for (i = 0; i < fp; ++i) { fp_again: k = ((k + 0x5125) ^ 0x3851) & 0xffff; for (j = 0; j < n; ++j) if (k == knownkeys[j]) goto fp_again; tick = timebase_count(); if (hashmap_find(mapkeys, m, k) >= 0) { fprintf(stderr, "hashmap_find false positive: i=%d/%d k=%04x\n", i, n, k); exit(1); } tock = timebase_count(); tacc += tock - tick; ++tcnt; } printf(" => %lums [%lu]\n", timebase_msec(&timebase, tacc), tcnt); printf("removing %d + verifying\n", n); tacc = 0; tcnt = 0; for (i = 0; i < n; ++i) { for (j = i; j < n; ++j) { k = knownkeys[j]; if (hashmap_find(mapkeys, m, k) < 0) { fprintf(stderr, "hashmap_find failed during removal: j=%d/%d k=%04x\n", j, n, k); exit(1); } } k = knownkeys[i]; tick = timebase_count(); if (hashmap_remove(mapkeys, m, k) < 0) { fprintf(stderr, "hashmap_find failed: i=%d/%d k=%04x\n", i, n, k); exit(1); } tock = timebase_count(); tacc += tock - tick; ++tcnt; } printf(" => %lums [%lu]\n", timebase_msec(&timebase, tacc), tcnt); free(knownkeys); free(mapkeys); free(mapvals); printf("OK\n"); }
static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, int argc, const char **argv) { char tmpdir[PATH_MAX]; struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT; struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT; struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT; struct strbuf wtdir = STRBUF_INIT; char *lbase_dir, *rbase_dir; size_t ldir_len, rdir_len, wtdir_len; const char *workdir, *tmp; int ret = 0, i; FILE *fp; struct hashmap working_tree_dups, submodules, symlinks2; struct hashmap_iter iter; struct pair_entry *entry; struct index_state wtindex; struct checkout lstate, rstate; int rc, flags = RUN_GIT_CMD, err = 0; struct child_process child = CHILD_PROCESS_INIT; const char *helper_argv[] = { "difftool--helper", NULL, NULL, NULL }; struct hashmap wt_modified, tmp_modified; int indices_loaded = 0; workdir = get_git_work_tree(); /* Setup temp directories */ tmp = getenv("TMPDIR"); xsnprintf(tmpdir, sizeof(tmpdir), "%s/git-difftool.XXXXXX", tmp ? tmp : "/tmp"); if (!mkdtemp(tmpdir)) return error("could not create '%s'", tmpdir); strbuf_addf(&ldir, "%s/left/", tmpdir); strbuf_addf(&rdir, "%s/right/", tmpdir); strbuf_addstr(&wtdir, workdir); if (!wtdir.len || !is_dir_sep(wtdir.buf[wtdir.len - 1])) strbuf_addch(&wtdir, '/'); mkdir(ldir.buf, 0700); mkdir(rdir.buf, 0700); memset(&wtindex, 0, sizeof(wtindex)); memset(&lstate, 0, sizeof(lstate)); lstate.base_dir = lbase_dir = xstrdup(ldir.buf); lstate.base_dir_len = ldir.len; lstate.force = 1; memset(&rstate, 0, sizeof(rstate)); rstate.base_dir = rbase_dir = xstrdup(rdir.buf); rstate.base_dir_len = rdir.len; rstate.force = 1; ldir_len = ldir.len; rdir_len = rdir.len; wtdir_len = wtdir.len; hashmap_init(&working_tree_dups, (hashmap_cmp_fn)working_tree_entry_cmp, NULL, 0); hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, NULL, 0); hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, NULL, 0); child.no_stdin = 1; child.git_cmd = 1; child.use_shell = 0; child.clean_on_exit = 1; child.dir = prefix; child.out = -1; argv_array_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z", NULL); for (i = 0; i < argc; i++) argv_array_push(&child.args, argv[i]); if (start_command(&child)) die("could not obtain raw diff"); fp = xfdopen(child.out, "r"); /* Build index info for left and right sides of the diff */ i = 0; while (!strbuf_getline_nul(&info, fp)) { int lmode, rmode; struct object_id loid, roid; char status; const char *src_path, *dst_path; if (starts_with(info.buf, "::")) die(N_("combined diff formats('-c' and '--cc') are " "not supported in\n" "directory diff mode('-d' and '--dir-diff').")); if (parse_index_info(info.buf, &lmode, &rmode, &loid, &roid, &status)) break; if (strbuf_getline_nul(&lpath, fp)) break; src_path = lpath.buf; i++; if (status != 'C' && status != 'R') { dst_path = src_path; } else { if (strbuf_getline_nul(&rpath, fp)) break; dst_path = rpath.buf; } if (S_ISGITLINK(lmode) || S_ISGITLINK(rmode)) { strbuf_reset(&buf); strbuf_addf(&buf, "Subproject commit %s", oid_to_hex(&loid)); add_left_or_right(&submodules, src_path, buf.buf, 0); strbuf_reset(&buf); strbuf_addf(&buf, "Subproject commit %s", oid_to_hex(&roid)); if (!oidcmp(&loid, &roid)) strbuf_addstr(&buf, "-dirty"); add_left_or_right(&submodules, dst_path, buf.buf, 1); continue; } if (S_ISLNK(lmode)) { char *content = get_symlink(&loid, src_path); add_left_or_right(&symlinks2, src_path, content, 0); free(content); } if (S_ISLNK(rmode)) { char *content = get_symlink(&roid, dst_path); add_left_or_right(&symlinks2, dst_path, content, 1); free(content); } if (lmode && status != 'C') { if (checkout_path(lmode, &loid, src_path, &lstate)) { ret = error("could not write '%s'", src_path); goto finish; } } if (rmode && !S_ISLNK(rmode)) { struct working_tree_entry *entry; /* Avoid duplicate working_tree entries */ FLEX_ALLOC_STR(entry, path, dst_path); hashmap_entry_init(entry, strhash(dst_path)); if (hashmap_get(&working_tree_dups, entry, NULL)) { free(entry); continue; } hashmap_add(&working_tree_dups, entry); if (!use_wt_file(workdir, dst_path, &roid)) { if (checkout_path(rmode, &roid, dst_path, &rstate)) { ret = error("could not write '%s'", dst_path); goto finish; } } else if (!is_null_oid(&roid)) { /* * Changes in the working tree need special * treatment since they are not part of the * index. */ struct cache_entry *ce2 = make_cache_entry(rmode, roid.hash, dst_path, 0, 0); add_index_entry(&wtindex, ce2, ADD_CACHE_JUST_APPEND); add_path(&rdir, rdir_len, dst_path); if (ensure_leading_directories(rdir.buf)) { ret = error("could not create " "directory for '%s'", dst_path); goto finish; } add_path(&wtdir, wtdir_len, dst_path); if (symlinks) { if (symlink(wtdir.buf, rdir.buf)) { ret = error_errno("could not symlink '%s' to '%s'", wtdir.buf, rdir.buf); goto finish; } } else { struct stat st; if (stat(wtdir.buf, &st)) st.st_mode = 0644; if (copy_file(rdir.buf, wtdir.buf, st.st_mode)) { ret = error("could not copy '%s' to '%s'", wtdir.buf, rdir.buf); goto finish; } } } } } fclose(fp); fp = NULL; if (finish_command(&child)) { ret = error("error occurred running diff --raw"); goto finish; } if (!i) goto finish; /* * Changes to submodules require special treatment.This loop writes a * temporary file to both the left and right directories to show the * change in the recorded SHA1 for the submodule. */ hashmap_iter_init(&submodules, &iter); while ((entry = hashmap_iter_next(&iter))) { if (*entry->left) { add_path(&ldir, ldir_len, entry->path); ensure_leading_directories(ldir.buf); write_file(ldir.buf, "%s", entry->left); } if (*entry->right) { add_path(&rdir, rdir_len, entry->path); ensure_leading_directories(rdir.buf); write_file(rdir.buf, "%s", entry->right); } } /* * Symbolic links require special treatment.The standard "git diff" * shows only the link itself, not the contents of the link target. * This loop replicates that behavior. */ hashmap_iter_init(&symlinks2, &iter); while ((entry = hashmap_iter_next(&iter))) { if (*entry->left) { add_path(&ldir, ldir_len, entry->path); ensure_leading_directories(ldir.buf); write_file(ldir.buf, "%s", entry->left); } if (*entry->right) { add_path(&rdir, rdir_len, entry->path); ensure_leading_directories(rdir.buf); write_file(rdir.buf, "%s", entry->right); } } strbuf_release(&buf); strbuf_setlen(&ldir, ldir_len); helper_argv[1] = ldir.buf; strbuf_setlen(&rdir, rdir_len); helper_argv[2] = rdir.buf; if (extcmd) { helper_argv[0] = extcmd; flags = 0; } else setenv("GIT_DIFFTOOL_DIRDIFF", "true", 1); rc = run_command_v_opt(helper_argv, flags); /* * If the diff includes working copy files and those * files were modified during the diff, then the changes * should be copied back to the working tree. * Do not copy back files when symlinks are used and the * external tool did not replace the original link with a file. * * These hashes are loaded lazily since they aren't needed * in the common case of --symlinks and the difftool updating * files through the symlink. */ hashmap_init(&wt_modified, (hashmap_cmp_fn)path_entry_cmp, NULL, wtindex.cache_nr); hashmap_init(&tmp_modified, (hashmap_cmp_fn)path_entry_cmp, NULL, wtindex.cache_nr); for (i = 0; i < wtindex.cache_nr; i++) { struct hashmap_entry dummy; const char *name = wtindex.cache[i]->name; struct stat st; add_path(&rdir, rdir_len, name); if (lstat(rdir.buf, &st)) continue; if ((symlinks && S_ISLNK(st.st_mode)) || !S_ISREG(st.st_mode)) continue; if (!indices_loaded) { static struct lock_file lock; strbuf_reset(&buf); strbuf_addf(&buf, "%s/wtindex", tmpdir); if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 || write_locked_index(&wtindex, &lock, COMMIT_LOCK)) { ret = error("could not write %s", buf.buf); rollback_lock_file(&lock); goto finish; } changed_files(&wt_modified, buf.buf, workdir); strbuf_setlen(&rdir, rdir_len); changed_files(&tmp_modified, buf.buf, rdir.buf); add_path(&rdir, rdir_len, name); indices_loaded = 1; } hashmap_entry_init(&dummy, strhash(name)); if (hashmap_get(&tmp_modified, &dummy, name)) { add_path(&wtdir, wtdir_len, name); if (hashmap_get(&wt_modified, &dummy, name)) { warning(_("both files modified: '%s' and '%s'."), wtdir.buf, rdir.buf); warning(_("working tree file has been left.")); warning("%s", ""); err = 1; } else if (unlink(wtdir.buf) || copy_file(wtdir.buf, rdir.buf, st.st_mode)) warning_errno(_("could not copy '%s' to '%s'"), rdir.buf, wtdir.buf); } } if (err) { warning(_("temporary files exist in '%s'."), tmpdir); warning(_("you may want to cleanup or recover these.")); exit(1); } else exit_cleanup(tmpdir, rc); finish: if (fp) fclose(fp); free(lbase_dir); free(rbase_dir); strbuf_release(&ldir); strbuf_release(&rdir); strbuf_release(&wtdir); strbuf_release(&buf); return ret; }
/* * Looks up or creates a cache entry for the specified key. */ static struct fsentry *fscache_get(struct fsentry *key) { struct fsentry *fse, *future, *waiter; EnterCriticalSection(&mutex); /* check if entry is in cache */ fse = fscache_get_wait(key); if (fse) { fsentry_addref(fse); LeaveCriticalSection(&mutex); return fse; } /* if looking for a file, check if directory listing is in cache */ if (!fse && key->list) { fse = fscache_get_wait(key->list); if (fse) { LeaveCriticalSection(&mutex); /* dir entry without file entry -> file doesn't exist */ errno = ENOENT; return NULL; } } /* add future entry to indicate that we're loading it */ future = key->list ? key->list : key; future->next = NULL; future->refcnt = 0; hashmap_add(&map, future); /* create the directory listing (outside mutex!) */ LeaveCriticalSection(&mutex); fse = fsentry_create_list(future); EnterCriticalSection(&mutex); /* remove future entry and signal waiting threads */ hashmap_remove(&map, future, NULL); waiter = future->next; while (waiter) { HANDLE h = waiter->hwait; waiter = waiter->next; SetEvent(h); } /* leave on error (errno set by fsentry_create_list) */ if (!fse) { LeaveCriticalSection(&mutex); return NULL; } /* add directory listing to the cache */ fscache_add(fse); /* lookup file entry if requested (fse already points to directory) */ if (key->list) fse = hashmap_get(&map, key, NULL); /* return entry or ENOENT */ if (fse) fsentry_addref(fse); else errno = ENOENT; LeaveCriticalSection(&mutex); return fse; }