Background search table population; fix #6984

This commit is contained in:
Charles Lindsay 2013-05-23 16:20:11 -07:00
parent a78f0c4a5f
commit f54ea44977
3 changed files with 83 additions and 41 deletions

View file

@ -24,6 +24,7 @@ private class Geary.ImapDB.Account : BaseObject {
private ImapDB.Database? db = null;
private Gee.HashMap<Geary.FolderPath, FolderReference> folder_refs =
new Gee.HashMap<Geary.FolderPath, FolderReference>();
private Cancellable? background_cancellable = null;
public ImapEngine.ContactStore contact_store { get; private set; }
public Account(Geary.AccountInformation account_information) {
@ -68,6 +69,11 @@ private class Geary.ImapDB.Account : BaseObject {
error("Error finding account from its information: %s", e.message);
}
background_cancellable = new Cancellable();
// Kick off a background update of the search table.
populate_search_table_async.begin(background_cancellable);
initialize_contacts(cancellable);
// ImapDB.Account holds the Outbox, which is tied to the database it maintains
@ -93,6 +99,9 @@ private class Geary.ImapDB.Account : BaseObject {
db = null;
}
background_cancellable.cancel();
background_cancellable = null;
outbox = null;
search_folder = null;
}
@ -684,6 +693,65 @@ private class Geary.ImapDB.Account : BaseObject {
debug("Deleted %d duplicate folders", count);
}
private async void populate_search_table_async(Cancellable? cancellable) {
// TODO: send processing signal upwards.
debug("Populating search table");
try {
while (!yield populate_search_table_batch_async(100, cancellable))
;
} catch (Error e) {
debug("Error populating search table: %s", e.message);
}
debug("Done populating search table");
}
private async bool populate_search_table_batch_async(int limit = 100,
Cancellable? cancellable) throws Error {
bool done = false;
yield db.exec_transaction_async(Db.TransactionType.RW, (cx, cancellable) => {
Db.Statement stmt = cx.prepare("""
SELECT id
FROM MessageTable
WHERE id NOT IN (
SELECT id
FROM MessageSearchTable
)
LIMIT ?
""");
stmt.bind_int(0, limit);
int count = 0;
Db.Result result = stmt.exec(cancellable);
while (!result.finished) {
int64 id = result.rowid_at(0);
try {
MessageRow row = Geary.ImapDB.Folder.do_fetch_message_row(
cx, id, Geary.ImapDB.Folder.REQUIRED_FOR_SEARCH, cancellable);
Geary.Email email = row.to_email(-1, new Geary.ImapDB.EmailIdentifier(id));
Geary.ImapDB.Folder.do_add_attachments(cx, email, id, cancellable);
Geary.ImapDB.Folder.do_add_email_to_search_table(cx, 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 %lld to the search table: %s", id, e.message);
}
++count;
result.next(cancellable);
}
if (count < limit)
done = true;
return Db.TransactionOutcome.DONE;
}, cancellable);
return done;
}
//
// Transaction helper methods
//

View file

@ -107,44 +107,6 @@ private class Geary.ImapDB.Database : Geary.Db.VersionedDatabase {
} catch (Error e) {
error("Error creating search table: %s", e.message);
}
bool done = false;
int limit = 100;
for (int offset = 0; !done; offset += limit) {
try {
exec_transaction(Db.TransactionType.RW, (cx) => {
Db.Statement stmt = prepare(
"SELECT id FROM MessageTable ORDER BY id LIMIT ? OFFSET ?");
stmt.bind_int(0, limit);
stmt.bind_int(1, offset);
Db.Result result = stmt.exec();
if (result.finished)
done = true;
while (!result.finished) {
int64 id = result.rowid_at(0);
try {
MessageRow row = Geary.ImapDB.Folder.do_fetch_message_row(
cx, id, Geary.ImapDB.Folder.REQUIRED_FOR_SEARCH, null);
Geary.Email email = row.to_email(-1, new Geary.ImapDB.EmailIdentifier(id));
Geary.ImapDB.Folder.do_add_attachments(cx, email, id);
Geary.ImapDB.Folder.do_add_email_to_search_table(cx, id, email, null);
} catch (Error e) {
debug("Error adding message %lld to the search table: %s", id, e.message);
}
result.next();
}
return Db.TransactionOutcome.DONE;
});
} catch (Error e) {
debug("Error populating search table: %s", e.message);
}
}
}
private void on_prepare_database_connection(Db.Connection cx) throws Error {

View file

@ -953,7 +953,16 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
stmt.bind_string(6, (email.cc != null ? email.cc.to_searchable_string() : null));
stmt.bind_string(7, (email.bcc != null ? email.bcc.to_searchable_string() : null));
stmt.exec_insert();
stmt.exec_insert(cancellable);
}
private static bool do_check_for_message_search_row(Db.Connection cx, int64 message_id,
Cancellable? cancellable) throws Error {
Db.Statement stmt = cx.prepare("SELECT 'TRUE' FROM MessageSearchTable WHERE id=?");
stmt.bind_rowid(0, message_id);
Db.Result result = stmt.exec(cancellable);
return !result.finished;
}
private Gee.List<Geary.Email>? do_list_email(Db.Connection cx, Gee.List<LocationIdentifier> locations,
@ -1309,7 +1318,7 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
stmt.bind_string(6, (email.bcc != null ? email.bcc.to_searchable_string() : null));
stmt.bind_rowid(7, message_id);
stmt.exec();
stmt.exec(cancellable);
}
private void do_merge_email(Db.Connection cx, int64 message_id, Geary.Email email,
@ -1344,7 +1353,10 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
}
}
do_merge_email_in_search_table(cx, message_id, combined_email, cancellable);
if (do_check_for_message_search_row(cx, message_id, cancellable))
do_merge_email_in_search_table(cx, message_id, combined_email, cancellable);
else
do_add_email_to_search_table(cx, message_id, combined_email, cancellable);
}
private static Gee.List<Geary.Attachment>? do_list_attachments(Db.Connection cx, int64 message_id,