Message ID | 20200731092323.763-4-anton.ivanov@cambridgegreys.com |
---|---|
State | Changes Requested |
Headers | show |
Series | [ovs-dev,1/3] Optimise shash disposal | expand |
On 7/31/20 11:23 AM, anton.ivanov@cambridgegreys.com wrote: > From: Anton Ivanov <anton.ivanov@cambridgegreys.com> > > shash_find_and_delete at present looks up an item using > shash_find then uses hmap_delete to delete it. > > As a result it computes the hash twice and does two walks of > the linked list in the bucket. > > This change unrolls the first walk to preserve extra information > making the second computation and walk unnecessary. > > Signed-off-by: Anton Ivanov <anton.ivanov@cambridgegreys.com> > --- > lib/shash.c | 36 ++++++++++++++++++++++++++++++------ > 1 file changed, 30 insertions(+), 6 deletions(-) > > diff --git a/lib/shash.c b/lib/shash.c > index f378d1656..d2793c2e7 100644 > --- a/lib/shash.c > +++ b/lib/shash.c > @@ -276,14 +276,38 @@ shash_find_data(const struct shash *sh, const char *name) > void * > shash_find_and_delete(struct shash *sh, const char *name) > { > - struct shash_node *node = shash_find(sh, name); > - if (node) { > - void *data = node->data; > - shash_delete(sh, node); > - return data; > - } else { > + struct shash_node *node; > + > + /* unroll shash_find and hmap_find */ > + > + struct hmap_node > + **bucket = &sh->map.buckets[hash_name(name) & sh->map.mask]; > + ssize_t name_len = strlen(name); > + > + while (*bucket != NULL) { > + node = CONTAINER_OF(*bucket, struct shash_node, node); > + if (!strncmp(node->name, name, name_len) && !node->name[name_len]) { > + break; > + } > + bucket = &(*bucket)->next; > + } > + > + if (*bucket == NULL) { > return NULL; > } > + > + void *data = node->data; > + > + /* use the underlying hmap node to do a direct hmap remove */ > + > + *bucket = node->node.next; > + sh->map.n--; > + > + /* unroll smap_steal and smap_delete */ > + > + free(node->name); > + free(node); > + return data; > } > > void * > Same as for patch1, shouldn't most of this be implemented in hmap? E.g., hmap_find_and_delete() which would return the node that was removed from the hmap? Thanks, Dumitru
diff --git a/lib/shash.c b/lib/shash.c index f378d1656..d2793c2e7 100644 --- a/lib/shash.c +++ b/lib/shash.c @@ -276,14 +276,38 @@ shash_find_data(const struct shash *sh, const char *name) void * shash_find_and_delete(struct shash *sh, const char *name) { - struct shash_node *node = shash_find(sh, name); - if (node) { - void *data = node->data; - shash_delete(sh, node); - return data; - } else { + struct shash_node *node; + + /* unroll shash_find and hmap_find */ + + struct hmap_node + **bucket = &sh->map.buckets[hash_name(name) & sh->map.mask]; + ssize_t name_len = strlen(name); + + while (*bucket != NULL) { + node = CONTAINER_OF(*bucket, struct shash_node, node); + if (!strncmp(node->name, name, name_len) && !node->name[name_len]) { + break; + } + bucket = &(*bucket)->next; + } + + if (*bucket == NULL) { return NULL; } + + void *data = node->data; + + /* use the underlying hmap node to do a direct hmap remove */ + + *bucket = node->node.next; + sh->map.n--; + + /* unroll smap_steal and smap_delete */ + + free(node->name); + free(node); + return data; } void *