It feels a bit fragile to me that we use hash_name() in some places and hash_bytes() in others. If the implementation of hash_string() changes, this is going to break. Minimally I think we should change hash_name() to use hash_bytes() directly instead of going through hash_string(). We could also just get rid of simap_find_len() which is the only direct caller of hash_bytes(), not sure if it will be used later or not.
s/freee()/free()/ The comment of simap_destroy() says it frees 'simap', when it actually only frees it's data. Looks good, thanks this will be useful. Ethan On Tue, May 8, 2012 at 3:47 PM, Ben Pfaff <b...@nicira.com> wrote: > This commit adapts a couple of existing pieces of code to use the > new data structure. The following commit will add another user > (which is also the first use of the simap_increas() function). > > Signed-off-by: Ben Pfaff <b...@nicira.com> > --- > lib/automake.mk | 2 + > lib/learning-switch.c | 7 +- > lib/learning-switch.h | 6 +- > lib/odp-util.c | 31 +++--- > lib/odp-util.h | 6 +- > lib/simap.c | 241 > ++++++++++++++++++++++++++++++++++++++++++++ > lib/simap.h | 70 +++++++++++++ > utilities/ovs-controller.c | 13 +-- > utilities/ovs-dpctl.c | 9 +- > 9 files changed, 349 insertions(+), 36 deletions(-) > create mode 100644 lib/simap.c > create mode 100644 lib/simap.h > > diff --git a/lib/automake.mk b/lib/automake.mk > index 6217526..920babd 100644 > --- a/lib/automake.mk > +++ b/lib/automake.mk > @@ -135,6 +135,8 @@ lib_libopenvswitch_a_SOURCES = \ > lib/sha1.h \ > lib/shash.c \ > lib/shash.h \ > + lib/simap.c \ > + lib/simap.h \ > lib/signals.c \ > lib/signals.h \ > lib/socket-util.c \ > diff --git a/lib/learning-switch.c b/lib/learning-switch.c > index 4e7ceda..595b7f0 100644 > --- a/lib/learning-switch.c > +++ b/lib/learning-switch.c > @@ -37,6 +37,7 @@ > #include "poll-loop.h" > #include "rconn.h" > #include "shash.h" > +#include "simap.h" > #include "timeval.h" > #include "vconn.h" > #include "vlog.h" > @@ -125,12 +126,12 @@ lswitch_create(struct rconn *rconn, const struct > lswitch_config *cfg) > hmap_init(&sw->queue_numbers); > shash_init(&sw->queue_names); > if (cfg->port_queues) { > - struct shash_node *node; > + struct simap_node *node; > > - SHASH_FOR_EACH (node, cfg->port_queues) { > + SIMAP_FOR_EACH (node, cfg->port_queues) { > struct lswitch_port *port = xmalloc(sizeof *port); > hmap_node_nullify(&port->hmap_node); > - port->queue_id = (uintptr_t) node->data; > + port->queue_id = node->data; > shash_add(&sw->queue_names, node->name, port); > } > } > diff --git a/lib/learning-switch.h b/lib/learning-switch.h > index e42aec1..c3c37f2 100644 > --- a/lib/learning-switch.h > +++ b/lib/learning-switch.h > @@ -1,5 +1,5 @@ > /* > - * Copyright (c) 2008, 2010, 2011 Nicira, Inc. > + * Copyright (c) 2008, 2010, 2011, 2012 Nicira, Inc. > * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > @@ -55,8 +55,8 @@ struct lswitch_config { > * specifying a particular queue. */ > uint32_t default_queue; > > - /* Maps from a port name to a queue_id (cast to void *). */ > - const struct shash *port_queues; > + /* Maps from a port name to a queue_id. */ > + const struct simap *port_queues; > }; > > struct lswitch *lswitch_create(struct rconn *, const struct lswitch_config > *); > diff --git a/lib/odp-util.c b/lib/odp-util.c > index fef42ba..c24045f 100644 > --- a/lib/odp-util.c > +++ b/lib/odp-util.c > @@ -32,7 +32,7 @@ > #include "ofpbuf.h" > #include "openvswitch/tunnel.h" > #include "packets.h" > -#include "shash.h" > +#include "simap.h" > #include "timeval.h" > #include "util.h" > #include "vlog.h" > @@ -49,7 +49,7 @@ VLOG_DEFINE_THIS_MODULE(odp_util); > * from another. */ > static const char *delimiters = ", \t\r\n"; > > -static int parse_odp_key_attr(const char *, const struct shash *port_names, > +static int parse_odp_key_attr(const char *, const struct simap *port_names, > struct ofpbuf *); > static void format_odp_key_attr(const struct nlattr *a, struct ds *ds); > > @@ -295,7 +295,7 @@ format_odp_actions(struct ds *ds, const struct nlattr > *actions, > } > > static int > -parse_odp_action(const char *s, const struct shash *port_names, > +parse_odp_action(const char *s, const struct simap *port_names, > struct ofpbuf *actions) > { > /* Many of the sscanf calls in this function use oversized destination > @@ -320,12 +320,11 @@ parse_odp_action(const char *s, const struct shash > *port_names, > > if (port_names) { > int len = strcspn(s, delimiters); > - struct shash_node *node; > + struct simap_node *node; > > - node = shash_find_len(port_names, s, len); > + node = simap_find_len(port_names, s, len); > if (node) { > - nl_msg_put_u32(actions, OVS_ACTION_ATTR_OUTPUT, > - (uintptr_t) node->data); > + nl_msg_put_u32(actions, OVS_ACTION_ATTR_OUTPUT, node->data); > return len; > } > } > @@ -468,7 +467,7 @@ parse_odp_action(const char *s, const struct shash > *port_names, > * Netlink attributes. On failure, no data is appended to 'actions'. Either > * way, 'actions''s data might be reallocated. */ > int > -odp_actions_from_string(const char *s, const struct shash *port_names, > +odp_actions_from_string(const char *s, const struct simap *port_names, > struct ofpbuf *actions) > { > size_t old_size; > @@ -785,7 +784,7 @@ ovs_frag_type_from_string(const char *s, enum > ovs_frag_type *type) > } > > static int > -parse_odp_key_attr(const char *s, const struct shash *port_names, > +parse_odp_key_attr(const char *s, const struct simap *port_names, > struct ofpbuf *key) > { > /* Many of the sscanf calls in this function use oversized destination > @@ -832,14 +831,14 @@ parse_odp_key_attr(const char *s, const struct shash > *port_names, > > if (port_names && !strncmp(s, "in_port(", 8)) { > const char *name; > - const struct shash_node *node; > + const struct simap_node *node; > int name_len; > > name = s + 8; > name_len = strcspn(s, ")"); > - node = shash_find_len(port_names, name, name_len); > + node = simap_find_len(port_names, name, name_len); > if (node) { > - nl_msg_put_u32(key, OVS_KEY_ATTR_IN_PORT, (uintptr_t) > node->data); > + nl_msg_put_u32(key, OVS_KEY_ATTR_IN_PORT, node->data); > return 8 + name_len + 1; > } > } > @@ -1116,15 +1115,15 @@ parse_odp_key_attr(const char *s, const struct shash > *port_names, > * data is appended to 'key'. Either way, 'key''s data might be > * reallocated. > * > - * If 'port_names' is nonnull, it points to an shash that maps from a port > name > - * to a port number cast to void *. (Port names may be used instead of port > - * numbers in in_port.) > + * If 'port_names' is nonnull, it points to an simap that maps from a port > name > + * to a port number. (Port names may be used instead of port numbers in > + * in_port.) > * > * On success, the attributes appended to 'key' are individually syntactically > * valid, but they may not be valid as a sequence. 'key' might, for example, > * have duplicated keys. odp_flow_key_to_flow() will detect those errors. */ > int > -odp_flow_key_from_string(const char *s, const struct shash *port_names, > +odp_flow_key_from_string(const char *s, const struct simap *port_names, > struct ofpbuf *key) > { > const size_t old_size = key->size; > diff --git a/lib/odp-util.h b/lib/odp-util.h > index 0ea801a..85dd146 100644 > --- a/lib/odp-util.h > +++ b/lib/odp-util.h > @@ -30,7 +30,7 @@ struct ds; > struct flow; > struct nlattr; > struct ofpbuf; > -struct shash; > +struct simap; > > #define OVSP_NONE ((uint16_t) -1) > > @@ -62,7 +62,7 @@ odp_port_to_ofp_port(uint16_t odp_port) > > void format_odp_actions(struct ds *, const struct nlattr *odp_actions, > size_t actions_len); > -int odp_actions_from_string(const char *, const struct shash *port_names, > +int odp_actions_from_string(const char *, const struct simap *port_names, > struct ofpbuf *odp_actions); > > /* Upper bound on the length of a nlattr-formatted flow key. The longest > @@ -92,7 +92,7 @@ struct odputil_keybuf { > }; > > void odp_flow_key_format(const struct nlattr *, size_t, struct ds *); > -int odp_flow_key_from_string(const char *s, const struct shash *port_names, > +int odp_flow_key_from_string(const char *s, const struct simap *port_names, > struct ofpbuf *); > > void odp_flow_key_from_flow(struct ofpbuf *, const struct flow *); > diff --git a/lib/simap.c b/lib/simap.c > new file mode 100644 > index 0000000..68e58c3 > --- /dev/null > +++ b/lib/simap.c > @@ -0,0 +1,241 @@ > +/* > + * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#include <config.h> > +#include "simap.h" > +#include <assert.h> > +#include "hash.h" > + > +static size_t hash_name(const char *); > +static struct simap_node *simap_find__(const struct simap *, > + const char *name, size_t name_len, > + size_t hash); > +static struct simap_node *simap_add_nocopy__(struct simap *, > + char *name, unsigned int data, > + size_t hash); > +static int compare_nodes_by_name(const void *a_, const void *b_); > + > +/* Initializes 'simap' as an empty string-to-integer map. */ > +void > +simap_init(struct simap *simap) > +{ > + hmap_init(&simap->map); > +} > + > +/* Frees 'simap' and all the mappings that it contains. */ > +void > +simap_destroy(struct simap *simap) > +{ > + if (simap) { > + simap_clear(simap); > + hmap_destroy(&simap->map); > + } > +} > + > +/* Exchanges the contents of 'a' and 'b'. */ > +void > +simap_swap(struct simap *a, struct simap *b) > +{ > + hmap_swap(&a->map, &b->map); > +} > + > +/* Adjusts 'simap' so that it is still valid after it has been moved around > in > + * memory (e.g. due to realloc()). */ > +void > +simap_moved(struct simap *simap) > +{ > + hmap_moved(&simap->map); > +} > + > +/* Removes all of the mappings from 'simap' and frees them. */ > +void > +simap_clear(struct simap *simap) > +{ > + struct simap_node *node, *next; > + > + SIMAP_FOR_EACH_SAFE (node, next, simap) { > + hmap_remove(&simap->map, &node->node); > + free(node->name); > + free(node); > + } > +} > + > +/* Returns true if 'simap' contains no mappings, false if it contains at > least > + * one. */ > +bool > +simap_is_empty(const struct simap *simap) > +{ > + return hmap_is_empty(&simap->map); > +} > + > +/* Returns the number of mappings in 'simap'. */ > +size_t > +simap_count(const struct simap *simap) > +{ > + return hmap_count(&simap->map); > +} > + > +/* Inserts a mapping from 'name' to 'data' into 'simap', replacing any > + * existing mapping for 'name'. Returns true if a new mapping was added, > + * false if an existing mapping's value was replaced. > + * > + * The caller retains ownership of 'name'. */ > +bool > +simap_put(struct simap *simap, const char *name, unsigned int data) > +{ > + size_t hash = hash_name(name); > + struct simap_node *node; > + > + node = simap_find__(simap, name, strlen(name), hash); > + if (node) { > + node->data = data; > + return false; > + } else { > + simap_add_nocopy__(simap, xstrdup(name), data, hash); > + return true; > + } > +} > + > +/* Increases the data value in the mapping for 'name' by 'amt', or inserts a > + * mapping from 'name' to 'amt' if no such mapping exists. Returns the > + * new total data value for the mapping. > + * > + * If 'amt' is zero, this function does nothing and returns 0. That is, this > + * function won't create a mapping with a initial value of 0. > + * > + * The caller retains ownership of 'name'. */ > +unsigned int > +simap_increase(struct simap *simap, const char *name, unsigned int amt) > +{ > + if (amt) { > + size_t hash = hash_name(name); > + struct simap_node *node; > + > + node = simap_find__(simap, name, strlen(name), hash); > + if (node) { > + node->data += amt; > + } else { > + node = simap_add_nocopy__(simap, xstrdup(name), amt, hash); > + } > + return node->data; > + } else { > + return 0; > + } > +} > + > +/* Deletes 'node' from 'simap' and frees its associated memory. */ > +void > +simap_delete(struct simap *simap, struct simap_node *node) > +{ > + hmap_remove(&simap->map, &node->node); > + free(node->name); > + free(node); > +} > + > +/* Searches 'simap' for a mapping with the given 'name'. Returns it, if > found, > + * or a null pointer if not. */ > +struct simap_node * > +simap_find(const struct simap *simap, const char *name) > +{ > + return simap_find_len(simap, name, strlen(name)); > +} > + > +/* Searches 'simap' for a mapping whose name is the first 'name_len' bytes > + * starting at 'name'. Returns it, if found, or a null pointer if not. */ > +struct simap_node * > +simap_find_len(const struct simap *simap, const char *name, size_t len) > +{ > + return simap_find__(simap, name, len, hash_bytes(name, len, 0)); > +} > + > +/* Searches 'simap' for a mapping with the given 'name'. Returns the > + * associated data value, if found, otherwise zero. */ > +unsigned int > +simap_get(const struct simap *simap, const char *name) > +{ > + struct simap_node *node = simap_find(simap, name); > + return node ? node->data : 0; > +} > + > +/* Returns an array that contains a pointer to each mapping in 'simap', > + * ordered alphabetically by name. The returned array has simap_count(simap) > + * elements. > + * > + * The caller is responsible for freeing the returned array (with freee()). > It > + * should not free the individual "simap_node"s in the array, because they > are > + * still part of 'simap'. */ > +const struct simap_node ** > +simap_sort(const struct simap *simap) > +{ > + if (simap_is_empty(simap)) { > + return NULL; > + } else { > + const struct simap_node **nodes; > + struct simap_node *node; > + size_t i, n; > + > + n = simap_count(simap); > + nodes = xmalloc(n * sizeof *nodes); > + i = 0; > + SIMAP_FOR_EACH (node, simap) { > + nodes[i++] = node; > + } > + assert(i == n); > + > + qsort(nodes, n, sizeof *nodes, compare_nodes_by_name); > + > + return nodes; > + } > +} > + > +static size_t > +hash_name(const char *name) > +{ > + return hash_string(name, 0); > +} > + > +static struct simap_node * > +simap_find__(const struct simap *simap, const char *name, size_t name_len, > + size_t hash) > +{ > + struct simap_node *node; > + > + HMAP_FOR_EACH_WITH_HASH (node, node, hash, &simap->map) { > + if (!strncmp(node->name, name, name_len) && !node->name[name_len]) { > + return node; > + } > + } > + return NULL; > +} > + > +static struct simap_node * > +simap_add_nocopy__(struct simap *simap, char *name, unsigned int data, > + size_t hash) > +{ > + struct simap_node *node = xmalloc(sizeof *node); > + node->name = name; > + node->data = data; > + hmap_insert(&simap->map, &node->node, hash); > + return node; > +} > + > +static int > +compare_nodes_by_name(const void *a_, const void *b_) > +{ > + const struct simap_node *const *a = a_; > + const struct simap_node *const *b = b_; > + return strcmp((*a)->name, (*b)->name); > +} > diff --git a/lib/simap.h b/lib/simap.h > new file mode 100644 > index 0000000..e7bf80b > --- /dev/null > +++ b/lib/simap.h > @@ -0,0 +1,70 @@ > +/* > + * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#ifndef SIMAP_H > +#define SIMAP_H 1 > + > +#include "hmap.h" > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +/* A map from strings to unsigned integers. */ > +struct simap { > + struct hmap map; /* Contains "struct simap_node"s. */ > +}; > + > +struct simap_node { > + struct hmap_node node; /* In struct simap's 'map' hmap. */ > + char *name; > + unsigned int data; > +}; > + > +#define SIMAP_INITIALIZER(SIMAP) { HMAP_INITIALIZER(&(SIMAP)->map) } > + > +#define SIMAP_FOR_EACH(SIMAP_NODE, SIMAP) \ > + HMAP_FOR_EACH (SIMAP_NODE, node, &(SIMAP)->map) > + > +#define SIMAP_FOR_EACH_SAFE(SIMAP_NODE, NEXT, SIMAP) \ > + HMAP_FOR_EACH_SAFE (SIMAP_NODE, NEXT, node, &(SIMAP)->map) > + > +void simap_init(struct simap *); > +void simap_destroy(struct simap *); > +void simap_swap(struct simap *, struct simap *); > +void simap_moved(struct simap *); > +void simap_clear(struct simap *); > + > +bool simap_is_empty(const struct simap *); > +size_t simap_count(const struct simap *); > + > +bool simap_put(struct simap *, const char *, unsigned int); > +unsigned int simap_increase(struct simap *, const char *, unsigned int); > + > +unsigned int simap_get(const struct simap *, const char *); > +struct simap_node *simap_find(const struct simap *, const char *); > +struct simap_node *simap_find_len(const struct simap *, > + const char *, size_t len); > + > +void simap_delete(struct simap *, struct simap_node *); > + > +const struct simap_node **simap_sort(const struct simap *); > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* simap.h */ > diff --git a/utilities/ovs-controller.c b/utilities/ovs-controller.c > index d70b630..aa4cf4e 100644 > --- a/utilities/ovs-controller.c > +++ b/utilities/ovs-controller.c > @@ -1,5 +1,5 @@ > /* > - * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc. > + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. > * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > @@ -33,7 +33,7 @@ > #include "openflow/openflow.h" > #include "poll-loop.h" > #include "rconn.h" > -#include "shash.h" > +#include "simap.h" > #include "stream-ssl.h" > #include "timeval.h" > #include "unixctl.h" > @@ -76,8 +76,8 @@ static bool mute = false; > /* -q, --queue: default OpenFlow queue, none if UINT32_MAX. */ > static uint32_t default_queue = UINT32_MAX; > > -/* -Q, --port-queue: map from port name to port number (cast to void *). */ > -static struct shash port_queues = SHASH_INITIALIZER(&port_queues); > +/* -Q, --port-queue: map from port name to port number. */ > +static struct simap port_queues = SIMAP_INITIALIZER(&port_queues); > > /* --with-flows: Flows to send to switch. */ > static struct ofputil_flow_mod *default_flows; > @@ -274,8 +274,7 @@ add_port_queue(char *s) > "\"<port-name>:<queue-id>\""); > } > > - if (!shash_add_once(&port_queues, port_name, > - (void *) (uintptr_t) atoi(queue_id))) { > + if (!simap_put(&port_queues, port_name, atoi(queue_id))) { > ovs_fatal(0, "<port-name> arguments for -Q or --port-queue must " > "be unique"); > } > @@ -398,7 +397,7 @@ parse_options(int argc, char *argv[]) > } > free(short_options); > > - if (!shash_is_empty(&port_queues) || default_queue != UINT32_MAX) { > + if (!simap_is_empty(&port_queues) || default_queue != UINT32_MAX) { > if (action_normal) { > ovs_error(0, "queue IDs are incompatible with -N or --normal; " > "not using OFPP_NORMAL"); > diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c > index 7c19116..6cb05b8 100644 > --- a/utilities/ovs-dpctl.c > +++ b/utilities/ovs-dpctl.c > @@ -1,5 +1,5 @@ > /* > - * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc. > + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. > * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > @@ -43,6 +43,7 @@ > #include "ofpbuf.h" > #include "packets.h" > #include "shash.h" > +#include "simap.h" > #include "sset.h" > #include "timeval.h" > #include "util.h" > @@ -826,7 +827,7 @@ sort_output_actions(struct nlattr *actions, size_t length) > static void > do_normalize_actions(int argc, char *argv[]) > { > - struct shash port_names; > + struct simap port_names; > struct ofpbuf keybuf; > struct flow flow; > struct ofpbuf odp_actions; > @@ -841,7 +842,7 @@ do_normalize_actions(int argc, char *argv[]) > > ds_init(&s); > > - shash_init(&port_names); > + simap_init(&port_names); > for (i = 3; i < argc; i++) { > char name[16]; > int number; > @@ -849,7 +850,7 @@ do_normalize_actions(int argc, char *argv[]) > > if (sscanf(argv[i], "%15[^=]=%d%n", name, &number, &n) > 0 && n > 0) { > uintptr_t n = number; > - shash_add(&port_names, name, (void *) n); > + simap_put(&port_names, name, n); > } else { > ovs_fatal(0, "%s: expected NAME=NUMBER", argv[i]); > } > -- > 1.7.2.5 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev