[geary] Improve database parallelization



commit 8dec339f2ec05bf717b81ed46eaa483899d33851
Author: Jim Nelson <jim yorba org>
Date:   Wed Jun 11 17:05:54 2014 -0700

    Improve database parallelization
    
    Prior attempts to use multiple threads to access the SQLite database
    failed due to locking reasons.  This re-attempt fixes this, alloc'ing
    four threads per database and slightly changing the locking strategy
    for read-write transactions.
    
    Part of the prior issues may have been an attempt to use a connection
    pool (this patch simply opens a new connection for each transaction,
    which for our purposes seems fine).  The read-write strategy of
    deferring locking until the write portion of the transaction was also
    too optimistic, causing transactions to stall in the middle of their
    operations.

 src/engine/db/db-database.vala          |   33 +++++++-----------------------
 src/engine/db/db-transaction-type.vala  |    2 +-
 src/engine/imap-db/imap-db-account.vala |    2 +-
 3 files changed, 10 insertions(+), 27 deletions(-)
---
diff --git a/src/engine/db/db-database.vala b/src/engine/db/db-database.vala
index 2ecfcfb..ba0beaa 100644
--- a/src/engine/db/db-database.vala
+++ b/src/engine/db/db-database.vala
@@ -17,9 +17,7 @@
  */
 
 public class Geary.Db.Database : Geary.Db.Context {
-    // Dealing with BUSY signal is a bear, and so for now concurrency is turned off
-    // http://redmine.yorba.org/issues/6460
-    public const int DEFAULT_MAX_CONCURRENCY = 1;
+    public const int DEFAULT_MAX_CONCURRENCY = 4;
     
     public File db_file { get; private set; }
     public DatabaseFlags flags { get; private set; }
@@ -42,7 +40,6 @@ public class Geary.Db.Database : Geary.Db.Context {
     private Connection? master_connection = null;
     private int outstanding_async_jobs = 0;
     private ThreadPool<TransactionAsyncJob>? thread_pool = null;
-    private Gee.LinkedList<Connection>? cx_pool = null;
     private unowned PrepareConnection? prepare_cb = null;
     
     public Database(File db_file) {
@@ -83,9 +80,6 @@ public class Geary.Db.Database : Geary.Db.Context {
                 thread_pool = new ThreadPool<TransactionAsyncJob>.with_owned_data(on_async_job,
                     DEFAULT_MAX_CONCURRENCY, true);
             }
-            
-            if (cx_pool == null)
-                cx_pool = new Gee.LinkedList<Connection>();
         } else {
             warning("SQLite not thread-safe: asynchronous queries will not be available");
         }
@@ -274,22 +268,15 @@ public class Geary.Db.Database : Geary.Db.Context {
     
     // This method must be thread-safe.
     private void on_async_job(owned TransactionAsyncJob job) {
-        // go to connection pool before creating a connection -- *never* use master connection for
-        // threaded operations
+        // *never* use master connection for threaded operations
         Connection? cx = null;
-        lock (cx_pool) {
-            cx = cx_pool.poll();
-        }
-        
         Error? open_err = null;
-        if (cx == null) {
-            try {
-                cx = open_connection();
-            } catch (Error err) {
-                open_err = err;
-                debug("Warning: unable to open database connection to %s, cancelling AsyncJob: %s",
-                    db_file.get_path(), err.message);
-            }
+        try {
+            cx = open_connection();
+        } catch (Error err) {
+            open_err = err;
+            debug("Warning: unable to open database connection to %s, cancelling AsyncJob: %s",
+                db_file.get_path(), err.message);
         }
         
         if (cx != null)
@@ -301,10 +288,6 @@ public class Geary.Db.Database : Geary.Db.Context {
             assert(outstanding_async_jobs > 0);
             --outstanding_async_jobs;
         }
-        
-        lock (cx_pool) {
-            cx_pool.offer(cx);
-        }
     }
     
     public override Database? get_database() {
diff --git a/src/engine/db/db-transaction-type.vala b/src/engine/db/db-transaction-type.vala
index bc367eb..651d43b 100644
--- a/src/engine/db/db-transaction-type.vala
+++ b/src/engine/db/db-transaction-type.vala
@@ -11,7 +11,7 @@ public enum Geary.Db.TransactionType {
     
     // coarse synonyms
     RO = DEFERRED,
-    RW = DEFERRED,
+    RW = IMMEDIATE,
     WR = EXCLUSIVE,
     WO = EXCLUSIVE;
     
diff --git a/src/engine/imap-db/imap-db-account.vala b/src/engine/imap-db/imap-db-account.vala
index ccb8e3a..49ee528 100644
--- a/src/engine/imap-db/imap-db-account.vala
+++ b/src/engine/imap-db/imap-db-account.vala
@@ -1472,7 +1472,7 @@ private class Geary.ImapDB.Account : BaseObject {
         unread_status, Cancellable? cancellable) throws Error {
         Gee.Map<Geary.FolderPath, int> unread_change = new Gee.HashMap<Geary.FolderPath, int>();
         
-        yield db.exec_transaction_async(Db.TransactionType.RO, (cx) => {
+        yield db.exec_transaction_async(Db.TransactionType.RW, (cx) => {
             foreach (ImapDB.EmailIdentifier id in unread_status.keys) {
                 Gee.Set<Geary.FolderPath>? paths = do_find_email_folders(
                     cx, id.message_id, true, cancellable);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]