diff mbox series

[ovs-dev,ovs] ovsdb idl: Try committing the pending txn in ovsdb_idl_loop_run.

Message ID 20200603165139.1107659-1-numans@ovn.org
State Superseded
Headers show
Series [ovs-dev,ovs] ovsdb idl: Try committing the pending txn in ovsdb_idl_loop_run. | expand

Commit Message

Numan Siddique June 3, 2020, 4:51 p.m. UTC
From: Numan Siddique <numans@ovn.org>

The function ovsdb_idl_loop_run(), after calling ovsdb_idl_run(),
returns a transaction object (of type 'struct ovsdb_idl_txn').
The returned transaction object can be NULL if there is a pending
transaction (loop->committing_txn) in the idl loop object.

Normally the clients of idl library, first call ovsdb_idl_loop_run(),
then do their own processing and create any idl transactions during
this processing and then finally call ovsdb_idl_loop_commit_and_wait().

If ovsdb_idl_loop_run() returns NULL transaction object, then much
of the processing done by the client gets wasted as in the case
of ovn-controller.

The client (in this case ovn-controller), can skip the processing
and instead call ovsdb_idl_loop_commit_and_wait() if the transaction
oject is NULL. But ovn-controller uses IDL tracking and it may
loose the tracked changes in that run.

This patch tries to improve this scenario, by checking if the
pending transaction can be committed in the ovsdb_idl_loop_run()
itself and if the pending transaction is cleared (because of the
response messages from ovsdb-server due to a transaction message
in the previous run), ovsdb_idl_loop_run() can return a valid
transaction object.

CC: Han Zhou <hzhou@ovn.org>
Signed-off-by: Numan Siddique <numans@ovn.org>
---
 lib/ovsdb-idl.c | 136 ++++++++++++++++++++++++++++++------------------
 1 file changed, 85 insertions(+), 51 deletions(-)

Comments

Han Zhou June 3, 2020, 11:13 p.m. UTC | #1
On Wed, Jun 3, 2020 at 9:51 AM <numans@ovn.org> wrote:
>
> From: Numan Siddique <numans@ovn.org>
>
> The function ovsdb_idl_loop_run(), after calling ovsdb_idl_run(),
> returns a transaction object (of type 'struct ovsdb_idl_txn').
> The returned transaction object can be NULL if there is a pending
> transaction (loop->committing_txn) in the idl loop object.
>
> Normally the clients of idl library, first call ovsdb_idl_loop_run(),
> then do their own processing and create any idl transactions during
> this processing and then finally call ovsdb_idl_loop_commit_and_wait().
>
> If ovsdb_idl_loop_run() returns NULL transaction object, then much
> of the processing done by the client gets wasted as in the case
> of ovn-controller.
>
> The client (in this case ovn-controller), can skip the processing
> and instead call ovsdb_idl_loop_commit_and_wait() if the transaction
> oject is NULL. But ovn-controller uses IDL tracking and it may
> loose the tracked changes in that run.
>
> This patch tries to improve this scenario, by checking if the
> pending transaction can be committed in the ovsdb_idl_loop_run()
> itself and if the pending transaction is cleared (because of the
> response messages from ovsdb-server due to a transaction message
> in the previous run), ovsdb_idl_loop_run() can return a valid
> transaction object.

Thanks Numan for addressing this. I think the patch is to trying to make
the TXN_SUCCESS take effect as early as when transaction "reply" is
received and handled in ovsdb_idl_loop_run(). The approach looks good to
me, but here is a comment below.

>
> CC: Han Zhou <hzhou@ovn.org>
> Signed-off-by: Numan Siddique <numans@ovn.org>
> ---
>  lib/ovsdb-idl.c | 136 ++++++++++++++++++++++++++++++------------------
>  1 file changed, 85 insertions(+), 51 deletions(-)
>
> diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
> index f54e360e3..400fa3077 100644
> --- a/lib/ovsdb-idl.c
> +++ b/lib/ovsdb-idl.c
> @@ -385,6 +385,7 @@ static void ovsdb_idl_send_cond_change(struct
ovsdb_idl *idl);
>  static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *);
>  static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *);
>  static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *);
> +static int ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop);
>
>  static void
>  ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class
*class,
> @@ -5340,6 +5341,12 @@ struct ovsdb_idl_txn *
>  ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
>  {
>      ovsdb_idl_run(loop->idl);
> +
> +    /* See if we can commit the loop->committing_txn. */
> +    if (loop->committing_txn) {
> +        ovsdb_idl_try_commit_loop_txn(loop);

This funciton calls poll_immediate_wake(). I think we shouldn't wake here.
It is necessary for ovsdb_idl_loop_commit_and_wait() but not here.

> +    }
> +
>      loop->open_txn = (loop->committing_txn
>                        || ovsdb_idl_get_seqno(loop->idl) ==
loop->skip_seqno
>                        ? NULL
> @@ -5347,6 +5354,83 @@ ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
>      return loop->open_txn;
>  }
>
> +/* Attempts to commit the current transaction, if one is open.
> + *
> + * If a transaction was open, in this or a previous iteration of the
main loop,
> + * and had not before finished committing (successfully or
unsuccessfully), the
> + * return value is one of:
> + *
> + *  1: The transaction committed successfully (or it did not change
anything in
> + *     the database).
> + *  0: The transaction failed.
> + * -1: The commit is still in progress.
> + *
> + * Thus, the return value is -1 if the transaction is in progress and
otherwise
> + * true for success, false for failure.
> + *
> + * (In the corner case where the IDL sends a transaction to the database
and
> + * the database commits it, and the connection between the IDL and the
database
> + * drops before the IDL receives the message confirming the commit, this
> + * function can return 0 even though the transaction succeeded.)
> + */
> +static int
> +ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop)
> +{
> +    if (!loop->committing_txn) {
> +        /* Not a meaningful return value: no transaction was in
progress. */
> +        return 1;
> +    }
> +
> +    int retval;
> +    struct ovsdb_idl_txn *txn = loop->committing_txn;
> +
> +    enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
> +    if (status != TXN_INCOMPLETE) {
> +        switch (status) {
> +        case TXN_TRY_AGAIN:
> +            /* We want to re-evaluate the database when it's changed from
> +             * the contents that it had when we started the commit.
 (That
> +             * might have already happened.) */
> +            loop->skip_seqno = loop->precommit_seqno;
> +            if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
> +                poll_immediate_wake();
> +            }
> +            retval = 0;
> +            break;
> +
> +        case TXN_SUCCESS:
> +            /* Possibly some work on the database was deferred because no
> +             * further transaction could proceed.  Wake up again. */
> +            retval = 1;
> +            loop->cur_cfg = loop->next_cfg;
> +            poll_immediate_wake();
> +            break;
> +
> +        case TXN_UNCHANGED:
> +            retval = 1;
> +            loop->cur_cfg = loop->next_cfg;
> +            break;
> +
> +        case TXN_ABORTED:
> +        case TXN_NOT_LOCKED:
> +        case TXN_ERROR:
> +            retval = 0;
> +            break;
> +
> +        case TXN_UNCOMMITTED:
> +        case TXN_INCOMPLETE:
> +        default:
> +            OVS_NOT_REACHED();
> +        }
> +        ovsdb_idl_txn_destroy(txn);
> +        loop->committing_txn = NULL;
> +    } else {
> +        retval = -1;
> +    }
> +
> +    return retval;
> +}
> +
>  /* Attempts to commit the current transaction, if one is open, and sets
up the
>   * poll loop to wake up when some more work might be needed.
>   *
> @@ -5377,57 +5461,7 @@ ovsdb_idl_loop_commit_and_wait(struct
ovsdb_idl_loop *loop)
>          loop->precommit_seqno = ovsdb_idl_get_seqno(loop->idl);
>      }
>
> -    struct ovsdb_idl_txn *txn = loop->committing_txn;
> -    int retval;
> -    if (txn) {
> -        enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
> -        if (status != TXN_INCOMPLETE) {
> -            switch (status) {
> -            case TXN_TRY_AGAIN:
> -                /* We want to re-evaluate the database when it's changed
from
> -                 * the contents that it had when we started the commit.
 (That
> -                 * might have already happened.) */
> -                loop->skip_seqno = loop->precommit_seqno;
> -                if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
> -                    poll_immediate_wake();
> -                }
> -                retval = 0;
> -                break;
> -
> -            case TXN_SUCCESS:
> -                /* Possibly some work on the database was deferred
because no
> -                 * further transaction could proceed.  Wake up again. */
> -                retval = 1;
> -                loop->cur_cfg = loop->next_cfg;
> -                poll_immediate_wake();
> -                break;
> -
> -            case TXN_UNCHANGED:
> -                retval = 1;
> -                loop->cur_cfg = loop->next_cfg;
> -                break;
> -
> -            case TXN_ABORTED:
> -            case TXN_NOT_LOCKED:
> -            case TXN_ERROR:
> -                retval = 0;
> -                break;
> -
> -            case TXN_UNCOMMITTED:
> -            case TXN_INCOMPLETE:
> -            default:
> -                OVS_NOT_REACHED();
> -            }
> -            ovsdb_idl_txn_destroy(txn);
> -            loop->committing_txn = NULL;
> -        } else {
> -            retval = -1;
> -        }
> -    } else {
> -        /* Not a meaningful return value: no transaction was in
progress. */
> -        retval = 1;
> -    }
> -
> +    int retval = ovsdb_idl_try_commit_loop_txn(loop);
>      ovsdb_idl_wait(loop->idl);
>
>      return retval;
> --
> 2.26.2
>
Numan Siddique June 4, 2020, 6:48 p.m. UTC | #2
On Thu, Jun 4, 2020 at 4:43 AM Han Zhou <hzhou@ovn.org> wrote:

> On Wed, Jun 3, 2020 at 9:51 AM <numans@ovn.org> wrote:
> >
> > From: Numan Siddique <numans@ovn.org>
> >
> > The function ovsdb_idl_loop_run(), after calling ovsdb_idl_run(),
> > returns a transaction object (of type 'struct ovsdb_idl_txn').
> > The returned transaction object can be NULL if there is a pending
> > transaction (loop->committing_txn) in the idl loop object.
> >
> > Normally the clients of idl library, first call ovsdb_idl_loop_run(),
> > then do their own processing and create any idl transactions during
> > this processing and then finally call ovsdb_idl_loop_commit_and_wait().
> >
> > If ovsdb_idl_loop_run() returns NULL transaction object, then much
> > of the processing done by the client gets wasted as in the case
> > of ovn-controller.
> >
> > The client (in this case ovn-controller), can skip the processing
> > and instead call ovsdb_idl_loop_commit_and_wait() if the transaction
> > oject is NULL. But ovn-controller uses IDL tracking and it may
> > loose the tracked changes in that run.
> >
> > This patch tries to improve this scenario, by checking if the
> > pending transaction can be committed in the ovsdb_idl_loop_run()
> > itself and if the pending transaction is cleared (because of the
> > response messages from ovsdb-server due to a transaction message
> > in the previous run), ovsdb_idl_loop_run() can return a valid
> > transaction object.
>
> Thanks Numan for addressing this. I think the patch is to trying to make
> the TXN_SUCCESS take effect as early as when transaction "reply" is
> received and handled in ovsdb_idl_loop_run(). The approach looks good to
> me, but here is a comment below.
>
> >
> > CC: Han Zhou <hzhou@ovn.org>
> > Signed-off-by: Numan Siddique <numans@ovn.org>
> > ---
> >  lib/ovsdb-idl.c | 136 ++++++++++++++++++++++++++++++------------------
> >  1 file changed, 85 insertions(+), 51 deletions(-)
> >
> > diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
> > index f54e360e3..400fa3077 100644
> > --- a/lib/ovsdb-idl.c
> > +++ b/lib/ovsdb-idl.c
> > @@ -385,6 +385,7 @@ static void ovsdb_idl_send_cond_change(struct
> ovsdb_idl *idl);
> >  static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *);
> >  static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *);
> >  static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *);
> > +static int ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop);
> >
> >  static void
> >  ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class
> *class,
> > @@ -5340,6 +5341,12 @@ struct ovsdb_idl_txn *
> >  ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
> >  {
> >      ovsdb_idl_run(loop->idl);
> > +
> > +    /* See if we can commit the loop->committing_txn. */
> > +    if (loop->committing_txn) {
> > +        ovsdb_idl_try_commit_loop_txn(loop);
>
> This funciton calls poll_immediate_wake(). I think we shouldn't wake here.
> It is necessary for ovsdb_idl_loop_commit_and_wait() but not here.
>

Thanks for the review. I've addressed this in v2 -
https://patchwork.ozlabs.org/project/openvswitch/patch/20200604184715.168340-1-numans@ovn.org/

Thanks
Numan


>
> > +    }
> > +
> >      loop->open_txn = (loop->committing_txn
> >                        || ovsdb_idl_get_seqno(loop->idl) ==
> loop->skip_seqno
> >                        ? NULL
> > @@ -5347,6 +5354,83 @@ ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
> >      return loop->open_txn;
> >  }
> >
> > +/* Attempts to commit the current transaction, if one is open.
> > + *
> > + * If a transaction was open, in this or a previous iteration of the
> main loop,
> > + * and had not before finished committing (successfully or
> unsuccessfully), the
> > + * return value is one of:
> > + *
> > + *  1: The transaction committed successfully (or it did not change
> anything in
> > + *     the database).
> > + *  0: The transaction failed.
> > + * -1: The commit is still in progress.
> > + *
> > + * Thus, the return value is -1 if the transaction is in progress and
> otherwise
> > + * true for success, false for failure.
> > + *
> > + * (In the corner case where the IDL sends a transaction to the database
> and
> > + * the database commits it, and the connection between the IDL and the
> database
> > + * drops before the IDL receives the message confirming the commit, this
> > + * function can return 0 even though the transaction succeeded.)
> > + */
> > +static int
> > +ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop)
> > +{
> > +    if (!loop->committing_txn) {
> > +        /* Not a meaningful return value: no transaction was in
> progress. */
> > +        return 1;
> > +    }
> > +
> > +    int retval;
> > +    struct ovsdb_idl_txn *txn = loop->committing_txn;
> > +
> > +    enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
> > +    if (status != TXN_INCOMPLETE) {
> > +        switch (status) {
> > +        case TXN_TRY_AGAIN:
> > +            /* We want to re-evaluate the database when it's changed
> from
> > +             * the contents that it had when we started the commit.
>  (That
> > +             * might have already happened.) */
> > +            loop->skip_seqno = loop->precommit_seqno;
> > +            if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
> > +                poll_immediate_wake();
> > +            }
> > +            retval = 0;
> > +            break;
> > +
> > +        case TXN_SUCCESS:
> > +            /* Possibly some work on the database was deferred because
> no
> > +             * further transaction could proceed.  Wake up again. */
> > +            retval = 1;
> > +            loop->cur_cfg = loop->next_cfg;
> > +            poll_immediate_wake();
> > +            break;
> > +
> > +        case TXN_UNCHANGED:
> > +            retval = 1;
> > +            loop->cur_cfg = loop->next_cfg;
> > +            break;
> > +
> > +        case TXN_ABORTED:
> > +        case TXN_NOT_LOCKED:
> > +        case TXN_ERROR:
> > +            retval = 0;
> > +            break;
> > +
> > +        case TXN_UNCOMMITTED:
> > +        case TXN_INCOMPLETE:
> > +        default:
> > +            OVS_NOT_REACHED();
> > +        }
> > +        ovsdb_idl_txn_destroy(txn);
> > +        loop->committing_txn = NULL;
> > +    } else {
> > +        retval = -1;
> > +    }
> > +
> > +    return retval;
> > +}
> > +
> >  /* Attempts to commit the current transaction, if one is open, and sets
> up the
> >   * poll loop to wake up when some more work might be needed.
> >   *
> > @@ -5377,57 +5461,7 @@ ovsdb_idl_loop_commit_and_wait(struct
> ovsdb_idl_loop *loop)
> >          loop->precommit_seqno = ovsdb_idl_get_seqno(loop->idl);
> >      }
> >
> > -    struct ovsdb_idl_txn *txn = loop->committing_txn;
> > -    int retval;
> > -    if (txn) {
> > -        enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
> > -        if (status != TXN_INCOMPLETE) {
> > -            switch (status) {
> > -            case TXN_TRY_AGAIN:
> > -                /* We want to re-evaluate the database when it's changed
> from
> > -                 * the contents that it had when we started the commit.
>  (That
> > -                 * might have already happened.) */
> > -                loop->skip_seqno = loop->precommit_seqno;
> > -                if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno)
> {
> > -                    poll_immediate_wake();
> > -                }
> > -                retval = 0;
> > -                break;
> > -
> > -            case TXN_SUCCESS:
> > -                /* Possibly some work on the database was deferred
> because no
> > -                 * further transaction could proceed.  Wake up again. */
> > -                retval = 1;
> > -                loop->cur_cfg = loop->next_cfg;
> > -                poll_immediate_wake();
> > -                break;
> > -
> > -            case TXN_UNCHANGED:
> > -                retval = 1;
> > -                loop->cur_cfg = loop->next_cfg;
> > -                break;
> > -
> > -            case TXN_ABORTED:
> > -            case TXN_NOT_LOCKED:
> > -            case TXN_ERROR:
> > -                retval = 0;
> > -                break;
> > -
> > -            case TXN_UNCOMMITTED:
> > -            case TXN_INCOMPLETE:
> > -            default:
> > -                OVS_NOT_REACHED();
> > -            }
> > -            ovsdb_idl_txn_destroy(txn);
> > -            loop->committing_txn = NULL;
> > -        } else {
> > -            retval = -1;
> > -        }
> > -    } else {
> > -        /* Not a meaningful return value: no transaction was in
> progress. */
> > -        retval = 1;
> > -    }
> > -
> > +    int retval = ovsdb_idl_try_commit_loop_txn(loop);
> >      ovsdb_idl_wait(loop->idl);
> >
> >      return retval;
> > --
> > 2.26.2
> >
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
diff mbox series

Patch

diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index f54e360e3..400fa3077 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -385,6 +385,7 @@  static void ovsdb_idl_send_cond_change(struct ovsdb_idl *idl);
 static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *);
 static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *);
 static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *);
+static int ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop);
 
 static void
 ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class,
@@ -5340,6 +5341,12 @@  struct ovsdb_idl_txn *
 ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
 {
     ovsdb_idl_run(loop->idl);
+
+    /* See if we can commit the loop->committing_txn. */
+    if (loop->committing_txn) {
+        ovsdb_idl_try_commit_loop_txn(loop);
+    }
+
     loop->open_txn = (loop->committing_txn
                       || ovsdb_idl_get_seqno(loop->idl) == loop->skip_seqno
                       ? NULL
@@ -5347,6 +5354,83 @@  ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
     return loop->open_txn;
 }
 
+/* Attempts to commit the current transaction, if one is open.
+ *
+ * If a transaction was open, in this or a previous iteration of the main loop,
+ * and had not before finished committing (successfully or unsuccessfully), the
+ * return value is one of:
+ *
+ *  1: The transaction committed successfully (or it did not change anything in
+ *     the database).
+ *  0: The transaction failed.
+ * -1: The commit is still in progress.
+ *
+ * Thus, the return value is -1 if the transaction is in progress and otherwise
+ * true for success, false for failure.
+ *
+ * (In the corner case where the IDL sends a transaction to the database and
+ * the database commits it, and the connection between the IDL and the database
+ * drops before the IDL receives the message confirming the commit, this
+ * function can return 0 even though the transaction succeeded.)
+ */
+static int
+ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop)
+{
+    if (!loop->committing_txn) {
+        /* Not a meaningful return value: no transaction was in progress. */
+        return 1;
+    }
+
+    int retval;
+    struct ovsdb_idl_txn *txn = loop->committing_txn;
+
+    enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
+    if (status != TXN_INCOMPLETE) {
+        switch (status) {
+        case TXN_TRY_AGAIN:
+            /* We want to re-evaluate the database when it's changed from
+             * the contents that it had when we started the commit.  (That
+             * might have already happened.) */
+            loop->skip_seqno = loop->precommit_seqno;
+            if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
+                poll_immediate_wake();
+            }
+            retval = 0;
+            break;
+
+        case TXN_SUCCESS:
+            /* Possibly some work on the database was deferred because no
+             * further transaction could proceed.  Wake up again. */
+            retval = 1;
+            loop->cur_cfg = loop->next_cfg;
+            poll_immediate_wake();
+            break;
+
+        case TXN_UNCHANGED:
+            retval = 1;
+            loop->cur_cfg = loop->next_cfg;
+            break;
+
+        case TXN_ABORTED:
+        case TXN_NOT_LOCKED:
+        case TXN_ERROR:
+            retval = 0;
+            break;
+
+        case TXN_UNCOMMITTED:
+        case TXN_INCOMPLETE:
+        default:
+            OVS_NOT_REACHED();
+        }
+        ovsdb_idl_txn_destroy(txn);
+        loop->committing_txn = NULL;
+    } else {
+        retval = -1;
+    }
+
+    return retval;
+}
+
 /* Attempts to commit the current transaction, if one is open, and sets up the
  * poll loop to wake up when some more work might be needed.
  *
@@ -5377,57 +5461,7 @@  ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *loop)
         loop->precommit_seqno = ovsdb_idl_get_seqno(loop->idl);
     }
 
-    struct ovsdb_idl_txn *txn = loop->committing_txn;
-    int retval;
-    if (txn) {
-        enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
-        if (status != TXN_INCOMPLETE) {
-            switch (status) {
-            case TXN_TRY_AGAIN:
-                /* We want to re-evaluate the database when it's changed from
-                 * the contents that it had when we started the commit.  (That
-                 * might have already happened.) */
-                loop->skip_seqno = loop->precommit_seqno;
-                if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
-                    poll_immediate_wake();
-                }
-                retval = 0;
-                break;
-
-            case TXN_SUCCESS:
-                /* Possibly some work on the database was deferred because no
-                 * further transaction could proceed.  Wake up again. */
-                retval = 1;
-                loop->cur_cfg = loop->next_cfg;
-                poll_immediate_wake();
-                break;
-
-            case TXN_UNCHANGED:
-                retval = 1;
-                loop->cur_cfg = loop->next_cfg;
-                break;
-
-            case TXN_ABORTED:
-            case TXN_NOT_LOCKED:
-            case TXN_ERROR:
-                retval = 0;
-                break;
-
-            case TXN_UNCOMMITTED:
-            case TXN_INCOMPLETE:
-            default:
-                OVS_NOT_REACHED();
-            }
-            ovsdb_idl_txn_destroy(txn);
-            loop->committing_txn = NULL;
-        } else {
-            retval = -1;
-        }
-    } else {
-        /* Not a meaningful return value: no transaction was in progress. */
-        retval = 1;
-    }
-
+    int retval = ovsdb_idl_try_commit_loop_txn(loop);
     ovsdb_idl_wait(loop->idl);
 
     return retval;