diff --git a/ovsdb/file.c b/ovsdb/file.c
index fdd5f8e35a44..4aafb3be8ab4 100644
--- a/ovsdb/file.c
+++ b/ovsdb/file.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2016 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2016, 2017 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -250,6 +250,7 @@ ovsdb_file_open__(const char *file_name,
         if (filep) {
             *filep = file;
         }
+        db->file = file;
     } else {
         ovsdb_log_close(log);
     }
@@ -500,10 +501,7 @@ ovsdb_file_read_schema(const char *file_name, struct ovsdb_schema **schemap)
     return ovsdb_file_open_log(file_name, OVSDB_LOG_READ_ONLY, NULL, schemap);
 }
 
-/* Replica implementation. */
-
 struct ovsdb_file {
-    struct ovsdb_replica replica;
     struct ovsdb *db;
     struct ovsdb_log *log;
     char *file_name;
@@ -512,8 +510,6 @@ struct ovsdb_file {
     unsigned int n_transactions;
 };
 
-static const struct ovsdb_replica_class ovsdb_file_class;
-
 static struct ovsdb_error *
 ovsdb_file_create(struct ovsdb *db, struct ovsdb_log *log,
                   const char *file_name,
@@ -535,26 +531,17 @@ ovsdb_file_create(struct ovsdb *db, struct ovsdb_log *log,
     }
 
     file = xmalloc(sizeof *file);
-    ovsdb_replica_init(&file->replica, &ovsdb_file_class);
     file->db = db;
     file->log = log;
     file->file_name = abs_name;
     file->last_compact = time_msec();
     file->next_compact = file->last_compact + COMPACT_MIN_MSEC;
     file->n_transactions = n_transactions;
-    ovsdb_add_replica(db, &file->replica);
 
     *filep = file;
     return NULL;
 }
 
-static struct ovsdb_file *
-ovsdb_file_cast(struct ovsdb_replica *replica)
-{
-    ovs_assert(replica->class == &ovsdb_file_class);
-    return CONTAINER_OF(replica, struct ovsdb_file, replica);
-}
-
 static bool
 ovsdb_file_change_cb(const struct ovsdb_row *old,
                      const struct ovsdb_row *new,
@@ -579,11 +566,10 @@ ovsdb_file_txn_annotate(struct json *json, const char *comment)
     return json;
 }
 
-static struct ovsdb_error *
-ovsdb_file_commit(struct ovsdb_replica *replica,
+struct ovsdb_error *
+ovsdb_file_commit(struct ovsdb_file *file,
                   const struct ovsdb_txn *txn, bool durable)
 {
-    struct ovsdb_file *file = ovsdb_file_cast(replica);
     struct ovsdb_file_txn ftxn;
     struct ovsdb_error *error;
 
@@ -764,20 +750,13 @@ exit:
     return error;
 }
 
-static void
-ovsdb_file_destroy(struct ovsdb_replica *replica)
+void
+ovsdb_file_destroy(struct ovsdb_file *file)
 {
-    struct ovsdb_file *file = ovsdb_file_cast(replica);
-
     ovsdb_log_close(file->log);
     free(file->file_name);
     free(file);
 }
-
-static const struct ovsdb_replica_class ovsdb_file_class = {
-    ovsdb_file_commit,
-    ovsdb_file_destroy
-};
 
 static void
 ovsdb_file_txn_init(struct ovsdb_file_txn *ftxn)
diff --git a/ovsdb/file.h b/ovsdb/file.h
index c6ca92621044..a9ef0585b261 100644
--- a/ovsdb/file.h
+++ b/ovsdb/file.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2016, 2017 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
 struct ovsdb;
 struct ovsdb_file;
 struct ovsdb_schema;
+struct ovsdb_txn;
 
 struct ovsdb_error *ovsdb_file_open(const char *file_name, bool read_only,
                                     struct ovsdb **, struct ovsdb_file **)
@@ -44,6 +45,10 @@ struct ovsdb_error *ovsdb_file_read_schema(const char *file_name,
                                            struct ovsdb_schema **)
     OVS_WARN_UNUSED_RESULT;
 
+struct ovsdb_error *ovsdb_file_commit(struct ovsdb_file *,
+                                      const struct ovsdb_txn *, bool durable);
+void ovsdb_file_destroy(struct ovsdb_file *);
+
 struct json *ovsdb_file_txn_annotate(struct json *, const char *comment);
 
 #endif /* ovsdb/file.h */
diff --git a/ovsdb/monitor.c b/ovsdb/monitor.c
index c0f9c557ab67..b2ecd109ed60 100644
--- a/ovsdb/monitor.c
+++ b/ovsdb/monitor.c
@@ -1573,7 +1573,7 @@ ovsdb_monitor_destroy(struct ovsdb_monitor *dbmon)
     free(dbmon);
 }
 
-static struct ovsdb_error *
+static void
 ovsdb_monitor_commit(struct ovsdb_replica *replica,
                      const struct ovsdb_txn *txn,
                      bool durable OVS_UNUSED)
@@ -1601,8 +1601,6 @@ ovsdb_monitor_commit(struct ovsdb_replica *replica,
         ovsdb_monitor_json_cache_flush(m);
         break;
     }
-
-    return NULL;
 }
 
 static void
diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c
index d8f441ad0728..213d0d4823e1 100644
--- a/ovsdb/ovsdb.c
+++ b/ovsdb/ovsdb.c
@@ -18,6 +18,7 @@
 #include "ovsdb.h"
 
 #include "column.h"
+#include "file.h"
 #include "openvswitch/json.h"
 #include "ovsdb-error.h"
 #include "ovsdb-parser.h"
@@ -328,6 +329,7 @@ ovsdb_create(struct ovsdb_schema *schema)
 
     db = xmalloc(sizeof *db);
     db->schema = schema;
+    db->file = NULL;
     ovs_list_init(&db->replicas);
     ovs_list_init(&db->triggers);
     db->run_triggers = false;
@@ -363,6 +365,11 @@ ovsdb_destroy(struct ovsdb *db)
     if (db) {
         struct shash_node *node;
 
+        /* Close the log. */
+        if (db->file) {
+            ovsdb_file_destroy(db->file);
+        }
+
         /* Remove all the replicas. */
         while (!ovs_list_is_empty(&db->replicas)) {
             struct ovsdb_replica *r
diff --git a/ovsdb/ovsdb.h b/ovsdb/ovsdb.h
index 89bbfa2512fa..06cd3a72e49e 100644
--- a/ovsdb/ovsdb.h
+++ b/ovsdb/ovsdb.h
@@ -56,6 +56,7 @@ bool ovsdb_schema_equal(const struct ovsdb_schema *,
 /* Database. */
 struct ovsdb {
     struct ovsdb_schema *schema;
+    struct ovsdb_file *file;    /* If nonnull, log for transactions. */
     struct ovs_list replicas;   /* Contains "struct ovsdb_replica"s. */
     struct shash tables;        /* Contains "struct ovsdb_table *"s. */
 
@@ -87,8 +88,8 @@ struct ovsdb_replica {
 };
 
 struct ovsdb_replica_class {
-    struct ovsdb_error *(*commit)(struct ovsdb_replica *,
-                                  const struct ovsdb_txn *, bool durable);
+    void (*commit)(struct ovsdb_replica *,
+                   const struct ovsdb_txn *, bool durable);
     void (*destroy)(struct ovsdb_replica *);
 };
 
diff --git a/ovsdb/transaction.c b/ovsdb/transaction.c
index f47d45fca397..ba17834aa633 100644
--- a/ovsdb/transaction.c
+++ b/ovsdb/transaction.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2017 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
 
 #include "bitmap.h"
 #include "openvswitch/dynamic-string.h"
+#include "file.h"
 #include "hash.h"
 #include "openvswitch/hmap.h"
 #include "openvswitch/json.h"
@@ -865,17 +866,16 @@ ovsdb_txn_commit_(struct ovsdb_txn *txn, bool durable)
     }
 
     /* Send the commit to each replica. */
-    LIST_FOR_EACH (replica, node, &txn->db->replicas) {
-        error = (replica->class->commit)(replica, txn, durable);
+    if (txn->db->file) {
+        error = ovsdb_file_commit(txn->db->file, txn, durable);
         if (error) {
-            /* We don't support two-phase commit so only the first replica is
-             * allowed to report an error. */
-            ovs_assert(&replica->node == txn->db->replicas.next);
-
             ovsdb_txn_abort(txn);
             return error;
         }
     }
+    LIST_FOR_EACH (replica, node, &txn->db->replicas) {
+        replica->class->commit(replica, txn, durable);
+    }
 
     /* Finalize commit. */
     txn->db->run_triggers = true;
