I agree, that would look a bit tidier. I'll send a patch.

On 3 June 2014 08:53, Ethan Jackson <et...@nicira.com> wrote:

> I'm wondering if it'd be cleaner to have ukey_create() return a locked
> ukey, and to pull the try_lock() into the critical section for the
> ukeys map?  I.E.
>
> lock_hmap()
> ukey = ukey_lookup()
> if (!ukey) {
>     //create and insert
> } else {
>     // trylock
> }
> unlock_hmap()
>
> What do you think?
>
>
>
> On Thu, May 29, 2014 at 6:38 PM, Joe Stringer <joestrin...@nicira.com>
> wrote:
> > This patch refactors the code around ukey creation and lookup to
> > simplify the code for callers. A new function ukey_acquire() combines
> > these functions and attempts to acquire a lock on the ukey. Failure to
> > acquire a lock on the ukey is usually a sign that another thread is
> > handling the same flow concurrently, which means the flow does not need
> > to be handled anyway.
> >
> > Signed-off-by: Joe Stringer <joestrin...@nicira.com>
> > ---
> >  ofproto/ofproto-dpif-upcall.c |   86
> ++++++++++++++++++-----------------------
> >  1 file changed, 37 insertions(+), 49 deletions(-)
> >
> > diff --git a/ofproto/ofproto-dpif-upcall.c
> b/ofproto/ofproto-dpif-upcall.c
> > index 1c82b6b..36e9d41 100644
> > --- a/ofproto/ofproto-dpif-upcall.c
> > +++ b/ofproto/ofproto-dpif-upcall.c
> > @@ -216,6 +216,12 @@ static void upcall_unixctl_set_flow_limit(struct
> unixctl_conn *conn, int argc,
> >
> >  static struct udpif_key *ukey_create(const struct nlattr *key, size_t
> key_len,
> >                                       long long int used);
> > +static struct udpif_key *ukey_lookup(struct udpif *udpif,
> > +                                     const struct nlattr *key, size_t
> key_len,
> > +                                     uint32_t hash);
> > +static bool ukey_acquire(struct udpif *udpif, const struct nlattr *key,
> > +                         size_t key_len, long long int used,
> > +                         struct udpif_key **result);
> >  static void ukey_delete(struct revalidator *, struct udpif_key *);
> >
> >  static atomic_bool enable_megaflows = ATOMIC_VAR_INIT(true);
> > @@ -983,8 +989,9 @@ handle_upcalls(struct handler *handler, struct
> upcall *upcalls,
> >
> >  /* Must be called with udpif->ukeys[hash %
> udpif->n_revalidators].mutex. */
> >  static struct udpif_key *
> > -ukey_lookup__(struct udpif *udpif, const struct nlattr *key, size_t
> key_len,
> > -              uint32_t hash)
> > +ukey_lookup(struct udpif *udpif, const struct nlattr *key, size_t
> key_len,
> > +            uint32_t hash)
> > +    OVS_REQUIRES(udpif->ukeys->mutex)
> >  {
> >      struct udpif_key *ukey;
> >      struct hmap *hmap = &udpif->ukeys[hash %
> udpif->n_revalidators].hmap;
> > @@ -998,21 +1005,8 @@ ukey_lookup__(struct udpif *udpif, const struct
> nlattr *key, size_t key_len,
> >  }
> >
> >  static struct udpif_key *
> > -ukey_lookup(struct udpif *udpif, const struct nlattr *key, size_t
> key_len,
> > -            uint32_t hash)
> > -{
> > -    struct udpif_key *ukey;
> > -    uint32_t idx = hash % udpif->n_revalidators;
> > -
> > -    ovs_mutex_lock(&udpif->ukeys[idx].mutex);
> > -    ukey = ukey_lookup__(udpif, key, key_len, hash);
> > -    ovs_mutex_unlock(&udpif->ukeys[idx].mutex);
> > -
> > -    return ukey;
> > -}
> > -
> > -static struct udpif_key *
> >  ukey_create(const struct nlattr *key, size_t key_len, long long int
> used)
> > +    OVS_NO_THREAD_SAFETY_ANALYSIS
> >  {
> >      struct udpif_key *ukey = xmalloc(sizeof *ukey);
> >      ovs_mutex_init(&ukey->mutex);
> > @@ -1020,38 +1014,47 @@ ukey_create(const struct nlattr *key, size_t
> key_len, long long int used)
> >      ukey->key = (struct nlattr *) &ukey->key_buf;
> >      memcpy(&ukey->key_buf, key, key_len);
> >      ukey->key_len = key_len;
> > -
> > -    ovs_mutex_lock(&ukey->mutex);
> >      ukey->mark = false;
> >      ukey->flow_exists = true;
> >      ukey->created = used ? used : time_msec();
> >      memset(&ukey->stats, 0, sizeof ukey->stats);
> >      ukey->xcache = NULL;
> > -    ovs_mutex_unlock(&ukey->mutex);
> >
> >      return ukey;
> >  }
> >
> > -/* Checks for a ukey in 'udpif->ukeys' with the same 'ukey->key' and
> 'hash',
> > - * and inserts 'ukey' if it does not exist.
> > +/* Searches for a ukey in 'udpif->ukeys' that matches 'key' and
> 'key_len' and
> > + * attempts to lock the ukey. If the ukey does not exist, create it.
> >   *
> > - * Returns true if 'ukey' was inserted into 'udpif->ukeys', false
> otherwise. */
> > + * Returns true on success, setting *result to the matching ukey and
> returning
> > + * it in a locked state. Otherwise, returns false and clears *result. */
> >  static bool
> > -udpif_insert_ukey(struct udpif *udpif, struct udpif_key *ukey, uint32_t
> hash)
> > +ukey_acquire(struct udpif *udpif, const struct nlattr *key, size_t
> key_len,
> > +             long long int used, struct udpif_key **result)
> > +    OVS_TRY_LOCK(true, (*result)->mutex)
> >  {
> > -    struct udpif_key *duplicate;
> > -    uint32_t idx = hash % udpif->n_revalidators;
> > +    struct udpif_key *ukey;
> > +    uint32_t hash, idx;
> >      bool ok;
> >
> > +    hash = hash_bytes(key, key_len, udpif->secret);
> > +    idx = hash % udpif->n_revalidators;
> > +
> >      ovs_mutex_lock(&udpif->ukeys[idx].mutex);
> > -    duplicate = ukey_lookup__(udpif, ukey->key, ukey->key_len, hash);
> > -    if (duplicate) {
> > +    ukey = ukey_lookup(udpif, key, key_len, hash);
> > +    if (!ukey) {
> > +        ukey = ukey_create(key, key_len, used);
> > +        hmap_insert(&udpif->ukeys[idx].hmap, &ukey->hmap_node, hash);
> > +    }
> > +    ovs_mutex_unlock(&udpif->ukeys[idx].mutex);
> > +
> > +    if (ovs_mutex_trylock(&ukey->mutex)) {
> >          ok = false;
> > +        *result = NULL;
> >      } else {
> > -        hmap_insert(&udpif->ukeys[idx].hmap, &ukey->hmap_node, hash);
> >          ok = true;
> > +        *result = ukey;
> >      }
> > -    ovs_mutex_unlock(&udpif->ukeys[idx].mutex);
> >
> >      return ok;
> >  }
> > @@ -1362,28 +1365,13 @@ revalidate(struct revalidator *revalidator)
> >
> >          for (f = flows; f < &flows[n_dumped]; f++) {
> >              long long int used = f->stats.used;
> > -            uint32_t hash = hash_bytes(f->key, f->key_len,
> udpif->secret);
> > -            struct udpif_key *ukey = ukey_lookup(udpif, f->key,
> f->key_len,
> > -                                                 hash);
> > +            struct udpif_key *ukey;
> >              bool already_dumped, mark;
> >
> > -            if (!ukey) {
> > -                ukey = ukey_create(key, key_len, used);
> > -                if (!udpif_insert_ukey(udpif, ukey, hash)) {
> > -                    /* The same ukey has already been created. This
> means that
> > -                     * another revalidator is processing this flow
> > -                     * concurrently, so don't bother processing it. */
> > -                    COVERAGE_INC(upcall_duplicate_flow);
> > -                    ukey_delete(NULL, ukey);
> > -                    continue;
> > -                }
> > -            }
> > -
> > -            if (ovs_mutex_trylock(&ukey->mutex)) {
> > -                /* The flow has been dumped, and is being handled by
> another
> > -                 * revalidator concurrently. This can occasionally
> occur if the
> > -                 * datapath is changed in the middle of a flow dump.
> Rather than
> > -                 * perform the same work twice, skip the flow this
> time. */
> > +            if (!ukey_acquire(udpif, f->key, f->key_len, used, &ukey)) {
> > +                /* We couldn't acquire the ukey. This means that
> > +                 * another revalidator is processing this flow
> > +                 * concurrently, so don't bother processing it. */
> >                  COVERAGE_INC(upcall_duplicate_flow);
> >                  continue;
> >              }
> > --
> > 1.7.10.4
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > http://openvswitch.org/mailman/listinfo/dev
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to