addressbook file backend: libdb must be initialized for concurrent read/write
authorPatrick Ohly <patrick.ohly@intel.com>
Mon, 16 May 2011 09:21:04 +0000 (11:21 +0200)
committerPatrick Ohly <patrick.ohly@intel.com>
Mon, 16 May 2011 15:24:30 +0000 (17:24 +0200)
Very bad performance (100% CPU load, several minutes run time) were
seen for multiple concurrent writes. gdb shows that libdb is
apparently busy polling while writing.

The libdb API docs for DB_ENV->open() imply that either DB_INIT_CDB or
DB_INIT_LOCK must be used in apps which are not read-only, like
EDS. This patch adds DB_INIT_CDB because it is simple and fixes the
performance problem.

In some rare cases, DB_INIT_LOCK might provide better performance by
allowing concurrent writes of independent data, but that seems too
complicated for not enough gain right now (must check for deadlocks).

addressbook/backends/file/e-book-backend-file.c

index 7f8f465..6f33d8d 100644 (file)
@@ -1143,7 +1143,18 @@ e_book_backend_file_load_source (EBookBackend           *backend,
                                (gpointer (*)(gpointer , gsize)) g_try_realloc,
                                g_free);
 
-               db_error = (*env->open) (env, NULL, DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_THREAD, 0);
+               /*
+                * We need either DB_INIT_CDB or DB_INIT_LOCK, because we will have
+                * multiple threads reading and writing concurrently without
+                * any locking above libdb.
+                *
+                * DB_INIT_CDB enforces multiple reader/single writer by locking inside
+                * the database. It is used instead of DB_INIT_LOCK because DB_INIT_LOCK
+                * may deadlock, which would have to be called in a separate thread.
+                * Considered too complicated for not enough gain (= concurrent writes)
+                * at this point.
+                */
+               db_error = (*env->open) (env, NULL, DB_INIT_CDB | DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_THREAD, 0);
                if (db_error != 0) {
                        env->close (env, 0);
                        g_warning ("db_env_open failed with %s", db_strerror (db_error));