diff options
author | Nick Mathewson <nickm@torproject.org> | 2007-08-01 15:57:48 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2007-08-01 15:57:48 +0000 |
commit | d5c78593d20d40e4801e7017a04d9d0ba85374f9 (patch) | |
tree | cc8916211ad7cab64c9420da3707daaeddf0f2d7 | |
parent | 484c8b776d6d3df9e3ef474ddd85d73b2da79594 (diff) | |
download | tor-d5c78593d20d40e4801e7017a04d9d0ba85374f9.tar.gz tor-d5c78593d20d40e4801e7017a04d9d0ba85374f9.zip |
r13873@Kushana: nickm | 2007-07-31 10:54:05 -0700
Split over-optimized digestmap_set code into a generic part and a digestmap-specific part.
svn:r11012
-rw-r--r-- | src/common/container.c | 49 | ||||
-rw-r--r-- | src/common/ht.h | 25 |
2 files changed, 47 insertions, 27 deletions
diff --git a/src/common/container.c b/src/common/container.c index c31a4d2713..a148af2663 100644 --- a/src/common/container.c +++ b/src/common/container.c @@ -769,8 +769,6 @@ digestmap_set(digestmap_t *map, const char *key, void *val) { #ifndef OPTIMIZED_DIGESTMAP_SET digestmap_entry_t *resolve; -#else - digestmap_entry_t **resolve_ptr; #endif digestmap_entry_t search; void *oldval; @@ -792,31 +790,28 @@ digestmap_set(digestmap_t *map, const char *key, void *val) return NULL; } #else - /* XXXX020 We spend up to 5% of our time in this function, so the code - * below is meant to optimize the check/alloc/set cycle by avoiding the - * two trips to the hash table that we do in the unoptimized code above. - * (Each of HT_INSERT and HT_FIND calls HT_SET_HASH and HT_FIND_P.) - * - * Unfortunately, doing this requires us to poke around inside hash-table - * internals. It would be nice to avoid that. */ - if (!map->head.hth_table || - map->head.hth_n_entries >= map->head.hth_load_limit) - digestmap_impl_HT_GROW((&map->head), map->head.hth_n_entries+1); - _HT_SET_HASH(&search, node, digestmap_entry_hash); - resolve_ptr = _digestmap_impl_HT_FIND_P(&map->head, &search); - if (*resolve_ptr) { - oldval = (*resolve_ptr)->val; - (*resolve_ptr)->val = val; - return oldval; - } else { - digestmap_entry_t *newent = tor_malloc_zero(sizeof(digestmap_entry_t)); - memcpy(newent->key, key, DIGEST_LEN); - newent->val = val; - newent->node.hte_hash = search.node.hte_hash; - *resolve_ptr = newent; - ++map->head.hth_n_entries; - return NULL; - } + /* We spend up to 5% of our time in this function, so the code below is + * meant to optimize the check/alloc/set cycle by avoiding the two trips to + * the hash table that we do in the unoptimized code above. (Each of + * HT_INSERT and HT_FIND calls HT_SET_HASH and HT_FIND_P.) + */ + _HT_FIND_OR_INSERT(digestmap_impl, node, digestmap_entry_hash, &(map->head), + digestmap_entry_t, &search, ptr, + { + /* we found an entry. */ + oldval = (*ptr)->val; + (*ptr)->val = val; + return oldval; + }, + { + /* We didn't find the entry. */ + digestmap_entry_t *newent = + tor_malloc_zero(sizeof(digestmap_entry_t)); + memcpy(newent->key, key, DIGEST_LEN); + newent->val = val; + _HT_FOI_INSERT(node, &(map->head), &search, newent, ptr); + return NULL; + }); #endif } diff --git a/src/common/ht.h b/src/common/ht.h index 72fe5e2cb0..095bca356b 100644 --- a/src/common/ht.h +++ b/src/common/ht.h @@ -382,6 +382,31 @@ ht_string_hash(const char *s) return 0; \ } +/** Implements an over-optimized "find and insert if absent" block; + * not meant for direct usage by typical code, or usage outside the critical + * path.*/ +#define _HT_FIND_OR_INSERT(name, field, hashfn, head, eltype, elm, var, y, n) \ + { \ + struct name *_##var##_head = head; \ + eltype **var; \ + if (!_##var##_head->hth_table || \ + _##var##_head->hth_n_entries >= _##var##_head->hth_load_limit) \ + name##_HT_GROW(_##var##_head, _##var##_head->hth_n_entries+1); \ + _HT_SET_HASH((elm), field, hashfn); \ + var = _##name##_HT_FIND_P(_##var##_head, (elm)); \ + if (*var) { \ + y; \ + } else { \ + n; \ + } \ + } +#define _HT_FOI_INSERT(field, head, elm, newent, var) \ + { \ + newent->field.hte_hash = (elm)->field.hte_hash; \ + *var = newent; \ + ++((head)->hth_n_entries); \ + } + /* * Copyright 2005, Nick Mathewson. Implementation logic is adapted from code * by Cristopher Clark, retrofit to allow drop-in memory management, and to |