[geary/cherry-pick-82f0ca8d] Merge branch 'mjog/db-result-timing' into 'mainline'
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/cherry-pick-82f0ca8d] Merge branch 'mjog/db-result-timing' into 'mainline'
- Date: Thu, 24 Sep 2020 22:57:38 +0000 (UTC)
commit 1b8c9349c626d215ef219296f1b35af393b2bc3f
Author: Michael Gratton <mike vee net>
Date: Thu Sep 24 22:54:30 2020 +0000
Merge branch 'mjog/db-result-timing' into 'mainline'
Database contention and locking redux
See merge request GNOME/geary!578
(cherry picked from commit 82f0ca8d0f38e2323449bd8fb26c9ee88afd176b)
3b6dd303 Geary.Db.Context: Update access to DatabaseConnections
a1d31847 Geary.Db.Result: Log large elapsed query times as a warning
485868d5 Geary.Db.DatabaseConnection: Check elapsed time for exec statements
0fa0d0ea Geary.Db.Statement: Minor code cleanup
940ca831 Geary.Db.Context: Remove separate `logging_parent` property
e39853db Geary.ImapEngine.GenericAccount: Set database logging parent per account
0f60c285 Geary.Db: Update SQL logging
915a38fa Geary.ImapDb.Account: Slice up search table population work better
3d8b86dd Geary.ImapDB.Folder: Drop create/merge batch size down
src/engine/db/db-connection.vala | 5 +-
src/engine/db/db-context.vala | 46 +++--
src/engine/db/db-database-connection.vala | 37 ++--
src/engine/db/db-database.vala | 16 +-
src/engine/db/db-result.vala | 53 +++---
src/engine/db/db-statement.vala | 39 ++--
src/engine/db/db-transaction-connection.vala | 11 +-
src/engine/imap-db/imap-db-account.vala | 205 ++++++++++++---------
src/engine/imap-db/imap-db-attachment.vala | 2 +-
src/engine/imap-db/imap-db-folder.vala | 2 +-
.../imap-engine/imap-engine-generic-account.vala | 2 +
11 files changed, 245 insertions(+), 173 deletions(-)
---
diff --git a/src/engine/db/db-connection.vala b/src/engine/db/db-connection.vala
index 4f0859e11..ebce27dc3 100644
--- a/src/engine/db/db-connection.vala
+++ b/src/engine/db/db-connection.vala
@@ -18,7 +18,7 @@
* A connection will be automatically closed when its last reference
* is dropped.
*/
-public interface Geary.Db.Connection : Context {
+public interface Geary.Db.Connection : BaseObject {
private const string PRAGMA_FOREIGN_KEYS = "foreign_keys";
private const string PRAGMA_RECURSIVE_TRIGGERS = "recursive_triggers";
@@ -278,7 +278,8 @@ public interface Geary.Db.Connection : Context {
*
* @see exec
*/
- public abstract Result query(string sql, GLib.Cancellable? cancellable = null)
+ public abstract Result query(string sql,
+ GLib.Cancellable? cancellable = null)
throws GLib.Error;
/**
diff --git a/src/engine/db/db-context.vala b/src/engine/db/db-context.vala
index 9bbb85038..7b8b9d654 100644
--- a/src/engine/db/db-context.vala
+++ b/src/engine/db/db-context.vala
@@ -16,16 +16,25 @@
public abstract class Geary.Db.Context : BaseObject, Logging.Source {
+ /** The GLib logging domain used by this class. */
+ public const string LOGGING_DOMAIN = Logging.DOMAIN + ".Db";
+
+
/**
- * Determines if SQL queries and results will be logged.
+ * Determines if SQL queries will be logged.
*
- * This will cause extremely verbose logging, so enable with care.
+ * This will cause verbose logging, so enable with care.
*/
public static bool enable_sql_logging = false;
- /** The GLib logging domain used by this class. */
- public const string LOGGING_DOMAIN = Logging.DOMAIN + ".Db";
+ /**
+ * Determines if SQL results will be logged.
+ *
+ * This will cause extremely verbose logging, so enable with extra care.
+ */
+ public static bool enable_result_logging = false;
+
/** {@inheritDoc} */
public string logging_domain {
@@ -33,34 +42,41 @@ public abstract class Geary.Db.Context : BaseObject, Logging.Source {
}
/** {@inheritDoc} */
- public Logging.Source? logging_parent { get { return _logging_parent; } }
- private weak Logging.Source? _logging_parent = null;
+ public abstract Logging.Source? logging_parent { get; }
- public virtual Database? get_database() {
+ internal virtual Database? get_database() {
return get_connection() != null ? get_connection().database : null;
}
- public virtual Connection? get_connection() {
+ internal virtual DatabaseConnection? get_connection() {
return get_statement() != null ? get_statement().connection : null;
}
- public virtual Statement? get_statement() {
+ internal virtual Statement? get_statement() {
return get_result() != null ? get_result().statement : null;
}
- public virtual Result? get_result() {
+ internal virtual Result? get_result() {
return null;
}
- /** {@inheritDoc} */
- public void set_logging_parent(Logging.Source parent) {
- this._logging_parent = parent;
- }
-
/** {@inheritDoc} */
public abstract Logging.State to_logging_state();
+
+ protected inline void check_elapsed(string message,
+ GLib.Timer timer)
+ throws DatabaseError {
+ var elapsed = timer.elapsed();
+ var threshold = (get_connection().busy_timeout * 1000.0) / 2.0;
+ if (threshold > 0 && elapsed > threshold) {
+ warning("%s: elapsed time: %lfs (>50%)", message, elapsed);
+ } else if (elapsed > 1.0) {
+ debug("%s: elapsed time: %lfs (>1s)", message, elapsed);
+ }
+ }
+
protected inline int throw_on_error(string? method, int result, string? raw = null) throws DatabaseError
{
return Db.throw_on_error(this, method, result, raw);
}
diff --git a/src/engine/db/db-database-connection.vala b/src/engine/db/db-database-connection.vala
index 4e7ceb788..29d52fd16 100644
--- a/src/engine/db/db-database-connection.vala
+++ b/src/engine/db/db-database-connection.vala
@@ -66,6 +66,11 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
public Database database { get { return this._database; } }
private weak Database _database;
+ /** {@inheritDoc} */
+ public override Logging.Source? logging_parent {
+ get { return this._database; }
+ }
+
/** {@inheritDoc} */
internal Sqlite.Database db { get { return this._db; } }
private Sqlite.Database _db;
@@ -118,9 +123,10 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
/** {@inheritDoc} */
public Statement prepare(string sql) throws DatabaseError {
- var prepared = new Statement(this, sql);
- prepared.set_logging_parent(this);
- return prepared;
+ if (Db.Context.enable_sql_logging) {
+ debug(sql);
+ }
+ return new Statement(this, sql);
}
/** {@inheritDoc} */
@@ -132,23 +138,28 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
/** {@inheritDoc} */
public void exec(string sql, GLib.Cancellable? cancellable = null)
throws GLib.Error {
+ check_cancelled("Connection.exec", cancellable);
if (Db.Context.enable_sql_logging) {
- debug("exec:\n\t%s", sql);
+ debug(sql);
}
-
- check_cancelled("Connection.exec", cancellable);
- throw_on_error("Connection.exec", db.exec(sql), sql);
+ var timer = new GLib.Timer();
+ throw_on_error("Connection.exec_file", this.db.exec(sql), sql);
+ check_elapsed("Query \"%s\"".printf(sql), timer);
}
/** {@inheritDoc} */
public void exec_file(GLib.File file, GLib.Cancellable? cancellable = null)
throws GLib.Error {
check_cancelled("Connection.exec_file", cancellable);
+ if (Db.Context.enable_sql_logging) {
+ debug(file.get_path());
+ }
string sql;
FileUtils.get_contents(file.get_path(), out sql);
-
- exec(sql, cancellable);
+ var timer = new GLib.Timer();
+ throw_on_error("Connection.exec_file", this.db.exec(sql), sql);
+ check_elapsed(file.get_path(), timer);
}
/**
@@ -255,13 +266,13 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
return yield job.wait_for_completion_async();
}
- public override Connection? get_connection() {
- return this;
- }
-
/** {@inheritDoc} */
public override Logging.State to_logging_state() {
return new Logging.State(this, "%u", this.cx_number);
}
+ internal override DatabaseConnection? get_connection() {
+ return this;
+ }
+
}
diff --git a/src/engine/db/db-database.vala b/src/engine/db/db-database.vala
index 592bd3066..df5bed216 100644
--- a/src/engine/db/db-database.vala
+++ b/src/engine/db/db-database.vala
@@ -57,6 +57,10 @@ public class Geary.Db.Database : Context {
}
}
+ /** {@inheritDoc} */
+ public override Logging.Source? logging_parent { get { return _logging_parent; } }
+ private weak Logging.Source? _logging_parent = null;
+
private DatabaseConnection? primary = null;
private int outstanding_async_jobs = 0;
private ThreadPool<TransactionAsyncJob>? thread_pool = null;
@@ -143,7 +147,6 @@ public class Geary.Db.Database : Context {
var cx = new DatabaseConnection(
this, Sqlite.OPEN_READWRITE, cancellable
);
- cx.set_logging_parent(this);
try {
// drop existing test table (in case created in prior failed open)
@@ -233,7 +236,6 @@ public class Geary.Db.Database : Context {
DatabaseConnection cx = new DatabaseConnection(
this, sqlite_flags, cancellable
);
- cx.set_logging_parent(this);
prepare_connection(cx);
return cx;
}
@@ -357,9 +359,9 @@ public class Geary.Db.Database : Context {
return yield job.wait_for_completion_async();
}
-
- public override Database? get_database() {
- return this;
+ /** Sets the logging parent context object for this database. */
+ public void set_logging_parent(Logging.Source parent) {
+ this._logging_parent = parent;
}
/** {@inheritDoc} */
@@ -386,6 +388,10 @@ public class Geary.Db.Database : Context {
this.thread_pool.add(new_job);
}
+ internal override Database? get_database() {
+ return this;
+ }
+
/**
* Hook for subclasses to modify a new SQLite connection before use.
*
diff --git a/src/engine/db/db-result.vala b/src/engine/db/db-result.vala
index 1ec3ed551..14dc71a96 100644
--- a/src/engine/db/db-result.vala
+++ b/src/engine/db/db-result.vala
@@ -8,14 +8,20 @@ public class Geary.Db.Result : Geary.Db.Context {
public bool finished { get; private set; default = false; }
+ /** The statement this result was generated from. */
public Statement statement { get; private set; }
+ /** The current row represented by this result. */
+ public uint64 row { get; private set; default = 0; }
+
+ /** {@inheritDoc} */
+ public override Logging.Source? logging_parent {
+ get { return this.statement; }
+ }
// This results in an automatic first next().
internal Result(Statement statement, Cancellable? cancellable) throws Error {
this.statement = statement;
- set_logging_parent(statement);
-
statement.was_reset.connect(on_query_finished);
statement.bindings_cleared.connect(on_query_finished);
@@ -37,13 +43,14 @@ public class Geary.Db.Result : Geary.Db.Context {
public bool next(Cancellable? cancellable = null) throws Error {
check_cancelled("Result.next", cancellable);
- if (!finished) {
- Timer timer = new Timer();
- finished = throw_on_error("Result.next", statement.stmt.step(), statement.sql) != Sqlite.ROW;
- if (timer.elapsed() > 1.0)
- debug("\n\nDB QUERY STEP \"%s\"\nelapsed=%lf\n\n", statement.sql, timer.elapsed());
-
- log_result(finished ? "NO ROW" : "ROW");
+ if (!this.finished) {
+ this.row++;
+ var timer = new GLib.Timer();
+ this.finished = throw_on_error(
+ "Result.next", statement.stmt.step(), statement.sql
+ ) != Sqlite.ROW;
+ check_elapsed("Result.next", timer);
+ log_result(this.finished ? "NO ROW" : "ROW");
}
return !finished;
@@ -294,26 +301,24 @@ public class Geary.Db.Result : Geary.Db.Context {
return column;
}
- public override Result? get_result() {
- return this;
- }
-
/** {@inheritDoc} */
public override Logging.State to_logging_state() {
- return new Logging.State(this, this.finished ? "finished" : "not finished");
+ return new Logging.State(
+ this,
+ "%llu, %s",
+ this.row,
+ this.finished ? "finished" : "!finished"
+ );
+ }
+
+ internal override Result? get_result() {
+ return this;
}
[PrintfFormat]
- private void log_result(string fmt, ...) {
- if (Db.Context.enable_sql_logging) {
- Statement? stmt = get_statement();
- if (stmt != null) {
- debug("%s\n\t<%s>",
- fmt.vprintf(va_list()),
- (stmt != null) ? "%.100s".printf(stmt.sql) : "no sql");
- } else {
- debug(fmt.vprintf(va_list()));
- }
+ private inline void log_result(string fmt, ...) {
+ if (Db.Context.enable_result_logging) {
+ debug(fmt.vprintf(va_list()));
}
}
diff --git a/src/engine/db/db-statement.vala b/src/engine/db/db-statement.vala
index 0a36dfb1e..072692ffb 100644
--- a/src/engine/db/db-statement.vala
+++ b/src/engine/db/db-statement.vala
@@ -9,15 +9,21 @@ private extern string? sqlite3_expanded_sql(Sqlite.Statement stmt);
public class Geary.Db.Statement : Context {
- public string sql {
- get { return this.stmt.sql(); }
+
+ public string sql { get; private set; }
+
+ /** {@inheritDoc} */
+ public override Logging.Source? logging_parent {
+ get { return this.connection; }
}
- public Connection connection { get; private set; }
+ internal DatabaseConnection connection { get; private set; }
internal Sqlite.Statement stmt;
private Gee.HashMap<string, int>? column_map = null;
+ private Gee.HashSet<Memory.Buffer> held_buffers = new Gee.HashSet<Memory.Buffer>();
+
/**
* Fired when the Statement is executed the first time (after creation or after a reset).
@@ -34,22 +40,21 @@ public class Geary.Db.Statement : Context {
*/
public signal void bindings_cleared();
- private Gee.HashSet<Memory.Buffer> held_buffers = new Gee.HashSet<Memory.Buffer>();
- internal Statement(Connection connection, string sql) throws DatabaseError {
+ internal Statement(DatabaseConnection connection, string sql)
+ throws DatabaseError {
this.connection = connection;
- throw_on_error("Statement.ctor", connection.db.prepare_v2(sql, -1, out stmt, null), sql);
+ this.sql = sql;
+ throw_on_error(
+ "Statement.ctor",
+ connection.db.prepare_v2(sql, -1, out stmt, null),
+ sql
+ );
}
/** Returns SQL for the statement with bound parameters expanded. */
public string? get_expanded_sql() {
- // Replace all this with `Sqlite.Statement.expanded_sql` is
- // readily available. See:
- // https://gitlab.gnome.org/GNOME/vala/merge_requests/74
- string* sqlite = sqlite3_expanded_sql(this.stmt);
- string? sql = sqlite;
- Sqlite.Memory.free((void*) sqlite);
- return sql;
+ return this.stmt.expanded_sql();
}
/**
@@ -271,13 +276,13 @@ public class Geary.Db.Statement : Context {
return this;
}
- public override Statement? get_statement() {
- return this;
- }
-
/** {@inheritDoc} */
public override Logging.State to_logging_state() {
return new Logging.State(this, this.sql);
}
+ internal override Statement? get_statement() {
+ return this;
+ }
+
}
diff --git a/src/engine/db/db-transaction-connection.vala b/src/engine/db/db-transaction-connection.vala
index 48244dbc7..ebdd18b42 100644
--- a/src/engine/db/db-transaction-connection.vala
+++ b/src/engine/db/db-transaction-connection.vala
@@ -9,7 +9,7 @@
/**
* A connection to the database for transactions.
*/
-internal class Geary.Db.TransactionConnection : Context, Connection {
+internal class Geary.Db.TransactionConnection : BaseObject, Connection {
/** {@inheritDoc} */
@@ -54,13 +54,4 @@ internal class Geary.Db.TransactionConnection : Context, Connection {
this.db_cx.exec_file(file, cancellable);
}
- public override Connection? get_connection() {
- return this;
- }
-
- /** {@inheritDoc} */
- public override Logging.State to_logging_state() {
- return new Logging.State(this, "");
- }
-
}
diff --git a/src/engine/imap-db/imap-db-account.vala b/src/engine/imap-db/imap-db-account.vala
index 99244dc26..54522b90e 100644
--- a/src/engine/imap-db/imap-db-account.vala
+++ b/src/engine/imap-db/imap-db-account.vala
@@ -955,8 +955,78 @@ private class Geary.ImapDB.Account : BaseObject {
public async void populate_search_table(Cancellable? cancellable) {
debug("%s: Populating search table", account_information.id);
+ // Since all queries involved can be quite extensive and this
+ // is not a time-critical operation, split them up
+
+ var search_ids = new Gee.HashSet<int64?>(
+ Collection.int64_hash_func,
+ Collection.int64_equal_func
+ );
+ var message_ids = new Gee.HashSet<int64?>(
+ Collection.int64_hash_func,
+ Collection.int64_equal_func
+ );
+ var unindexed_message_ids = new Gee.HashSet<int64?>(
+ Collection.int64_hash_func,
+ Collection.int64_equal_func
+ );
+
try {
- while (!yield populate_search_table_batch_async(50, cancellable)) {
+ yield this.db.exec_transaction_async(
+ RO,
+ (cx, cancellable) => {
+ // Embedding a SELECT within a SELECT is painfully slow
+ // with SQLite, and a LEFT OUTER JOIN will still take in
+ // the order of seconds, so manually perform the operation
+
+ var result = cx.prepare(
+ "SELECT docid FROM MessageSearchTable"
+ ).exec(cancellable);
+ while (!result.finished) {
+ search_ids.add(result.rowid_at(0));
+ result.next(cancellable);
+ }
+
+ var stmt = cx.prepare(
+ "SELECT id FROM MessageTable WHERE (fields & ?) = ?"
+ );
+ stmt.bind_uint(0, Geary.ImapDB.Folder.REQUIRED_FTS_FIELDS);
+ stmt.bind_uint(1, Geary.ImapDB.Folder.REQUIRED_FTS_FIELDS);
+ result = stmt.exec(cancellable);
+ while (!result.finished) {
+ message_ids.add(result.rowid_at(0));
+ result.next(cancellable);
+ }
+
+ return DONE;
+ },
+ cancellable
+ );
+
+ // Run this in a separate thread since it could be quite a
+ // substantial process for large accounts
+ yield Nonblocking.Concurrent.global.schedule_async(
+ () => {
+ foreach (int64 message_id in message_ids) {
+ if (!search_ids.contains(message_id)) {
+ unindexed_message_ids.add(message_id);
+ }
+ }
+ },
+ cancellable
+ );
+
+ debug("%s: Found %d missing messages to populate",
+ this.account_information.id,
+ unindexed_message_ids.size
+ );
+
+ // Do the actual updating in batches since these require
+ // RW transactions
+ while (!unindexed_message_ids.is_empty) {
+ yield populate_search_table_batch_async(
+ 50, unindexed_message_ids, cancellable
+ );
// With multiple accounts, meaning multiple background threads
// doing such CPU- and disk-heavy work, this process can cause
// the main thread to slow to a crawl. This delay means the
@@ -965,105 +1035,70 @@ private class Geary.ImapDB.Account : BaseObject {
yield Geary.Scheduler.sleep_ms_async(50);
}
} catch (Error e) {
- debug("Error populating %s search table: %s", account_information.id, e.message);
+ debug("%s: Error populating search table: %s", account_information.id, e.message);
}
debug("%s: Done populating search table", account_information.id);
}
- private static Gee.HashSet<int64?> do_build_rowid_set(Db.Result result, Cancellable? cancellable)
- throws Error {
- Gee.HashSet<int64?> rowid_set = new Gee.HashSet<int64?>(Collection.int64_hash_func,
- Collection.int64_equal_func);
- while (!result.finished) {
- rowid_set.add(result.rowid_at(0));
- result.next(cancellable);
- }
-
- return rowid_set;
- }
-
- private async bool populate_search_table_batch_async(int limit, Cancellable? cancellable)
- throws Error {
+ private async void populate_search_table_batch_async(
+ int limit,
+ Gee.HashSet<int64?> unindexed_message_ids,
+ GLib.Cancellable? cancellable
+ ) throws GLib.Error {
check_open();
- debug("%s: Searching for up to %d missing indexed messages...", account_information.id,
- limit);
-
- int count = 0, total_unindexed = 0;
- yield db.exec_transaction_async(Db.TransactionType.RW, (cx, cancellable) => {
- // Embedding a SELECT within a SELECT is painfully slow
- // with SQLite, and a LEFT OUTER JOIN will still take in
- // the order of seconds, so manually perform the operation
- Db.Statement stmt = cx.prepare("""
- SELECT docid FROM MessageSearchTable
- """);
- Gee.HashSet<int64?> search_ids = do_build_rowid_set(stmt.exec(cancellable), cancellable);
-
- stmt = cx.prepare("""
- SELECT id FROM MessageTable WHERE (fields & ?) = ?
- """);
- stmt.bind_uint(0, Geary.ImapDB.Folder.REQUIRED_FTS_FIELDS);
- stmt.bind_uint(1, Geary.ImapDB.Folder.REQUIRED_FTS_FIELDS);
- Gee.HashSet<int64?> message_ids = do_build_rowid_set(stmt.exec(cancellable), cancellable);
-
- // This is hard to calculate correctly without doing a
- // join (which we should above, but is currently too
- // slow), and if we do get it wrong the progress monitor
- // will crash and burn, so just something too big to fail
- // for now. See Bug 776383.
- total_unindexed = message_ids.size;
-
- // chaff out any MessageTable entries not present in the MessageSearchTable ... since
- // we're given a limit, stuff messages req'ing search into separate set and stop when limit
- // reached
- Gee.HashSet<int64?> unindexed_message_ids = new Gee.HashSet<int64?>(Collection.int64_hash_func,
- Collection.int64_equal_func);
- foreach (int64 message_id in message_ids) {
- if (search_ids.contains(message_id))
- continue;
-
- unindexed_message_ids.add(message_id);
- if (unindexed_message_ids.size >= limit)
- break;
- }
-
- // For all remaining MessageTable rowid's, generate search table entry
- foreach (int64 message_id in unindexed_message_ids) {
- try {
- Geary.Email.Field search_fields = Geary.Email.REQUIRED_FOR_MESSAGE |
- Geary.Email.Field.ORIGINATORS | Geary.Email.Field.RECEIVERS |
- Geary.Email.Field.SUBJECT;
+ uint count = 0;
+ var iter = unindexed_message_ids.iterator();
+ yield this.db.exec_transaction_async(
+ RW,
+ (cx, cancellable) => {
+ while (iter.has_next() && count < limit) {
+ iter.next();
+ int64 message_id = iter.get();
+ try {
+ Email.Field search_fields = (
+ Email.REQUIRED_FOR_MESSAGE |
+ Email.Field.ORIGINATORS |
+ Email.Field.RECEIVERS |
+ Email.Field.SUBJECT
+ );
- Geary.Email.Field db_fields;
- MessageRow row = Geary.ImapDB.Folder.do_fetch_message_row(
- cx, message_id, search_fields, out db_fields, cancellable);
- Geary.Email email = row.to_email(new Geary.ImapDB.EmailIdentifier(message_id, null));
- Attachment.add_attachments(
- cx, this.db.attachments_path, email, message_id, cancellable
- );
+ Email.Field db_fields;
+ MessageRow row = Geary.ImapDB.Folder.do_fetch_message_row(
+ cx, message_id, search_fields, out db_fields, cancellable
+ );
+ Email email = row.to_email(
+ new Geary.ImapDB.EmailIdentifier(message_id, null)
+ );
+ Attachment.add_attachments(
+ cx, this.db.attachments_path, email, message_id, cancellable
+ );
+ Geary.ImapDB.Folder.do_add_email_to_search_table(
+ cx, message_id, email, cancellable
+ );
+ } catch (GLib.Error e) {
+ // This is a somewhat serious issue since we rely on
+ // there always being a row in the search table for
+ // every message.
+ warning(
+ "Error populating message %s for indexing: %s",
+ message_id.to_string(),
+ e.message
+ );
+ }
- Geary.ImapDB.Folder.do_add_email_to_search_table(cx, message_id, email, cancellable);
- } catch (Error e) {
- // This is a somewhat serious issue since we rely on
- // there always being a row in the search table for
- // every message.
- warning("Error adding message %s to the search table: %s", message_id.to_string(),
- e.message);
+ iter.remove();
+ ++count;
}
- ++count;
- }
-
- return Db.TransactionOutcome.DONE;
+ return COMMIT;
}, cancellable);
if (count > 0) {
- debug("%s: Found %d/%d missing indexed messages, %d remaining...",
- account_information.id, count, limit, total_unindexed);
+ debug("%s: Populated %u missing indexed messages...",
+ account_information.id, count);
}
-
- return (count < limit);
}
//
diff --git a/src/engine/imap-db/imap-db-attachment.vala b/src/engine/imap-db/imap-db-attachment.vala
index d8e8f9dbc..fa94b6300 100644
--- a/src/engine/imap-db/imap-db-attachment.vala
+++ b/src/engine/imap-db/imap-db-attachment.vala
@@ -245,7 +245,7 @@ private class Geary.ImapDB.Attachment : Geary.Attachment {
}
// Ensure they're dead, Jim.
- Db.Statement stmt = new Db.Statement(cx, """
+ Db.Statement stmt = cx.prepare("""
DELETE FROM MessageAttachmentTable WHERE message_id = ?
""");
stmt.bind_rowid(0, message_id);
diff --git a/src/engine/imap-db/imap-db-folder.vala b/src/engine/imap-db/imap-db-folder.vala
index 4b015cd17..2c2d4015b 100644
--- a/src/engine/imap-db/imap-db-folder.vala
+++ b/src/engine/imap-db/imap-db-folder.vala
@@ -40,7 +40,7 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
private const int LIST_EMAIL_METADATA_COUNT = 100;
private const int LIST_EMAIL_FIELDS_CHUNK_COUNT = 500;
private const int REMOVE_COMPLETE_LOCATIONS_CHUNK_COUNT = 500;
- private const int CREATE_MERGE_EMAIL_CHUNK_COUNT = 25;
+ private const int CREATE_MERGE_EMAIL_CHUNK_COUNT = 10;
private const int OLD_MSG_DETACH_BATCH_SIZE = 1000;
// When old messages beyond the period set in the account preferences are removed this number
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala
b/src/engine/imap-engine/imap-engine-generic-account.vala
index 2bd087b17..ef1ba7b4d 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -79,6 +79,8 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
base(config, imap, smtp);
this.local = local;
+ this.local.db.set_logging_parent(this);
+
this.contact_store = new ContactStoreImpl(local.db);
imap.min_pool_size = IMAP_MIN_POOL_SIZE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]