Problems with replay queue when folder closes: Closes #5825, Closes #5824

Commit 327d183b (closing #5571) introduced regressions when a folder
is closing or closed.  This patch addresses two problems, one a crasher
and the other a case where the replay queue simply never closed when
requested.
This commit is contained in:
Jim Nelson 2012-09-17 14:49:54 -07:00
parent 9867509f91
commit 3723a5cdd4
3 changed files with 54 additions and 26 deletions

View file

@ -474,8 +474,15 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
debug("Unable to fire semaphore notifying remote folder ready/not ready: %s",
notify_err.message);
remote_folder = null;
remote_count = -1;
// do this now rather than wait for close_internal_async() to execute to ensure that
// any replay operations already queued don't attempt to run
try {
clear_remote_folder();
} catch (Error err) {
debug("Unable to clear and signal remote folder due to failed open: %s", err.message);
// fall through
}
notify_open_failed(Geary.Folder.OpenFailed.REMOTE_FAILED, notify_err);
@ -506,11 +513,8 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
// Notify all callers waiting for the remote folder that it's not coming available
Imap.Folder? closing_remote_folder = remote_folder;
remote_folder = null;
remote_count = -1;
try {
remote_semaphore.notify();
clear_remote_folder();
} catch (Error err) {
debug("close_internal_async: Unable to fire remote semaphore: %s", err.message);
}
@ -563,6 +567,14 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
debug("Folder %s closed", to_string());
}
private void clear_remote_folder() throws Error {
remote_folder = null;
remote_count = -1;
remote_semaphore.reset();
remote_semaphore.notify_result(false, null);
}
private void on_remote_messages_appended(int total) {
debug("on_remote_messages_appended: total=%d", total);
replay_queue.schedule(new ReplayAppend(this, total));

View file

@ -108,6 +108,13 @@ private class Geary.ImapEngine.ReplayQueue {
Logging.debug(Logging.Flag.REPLAY, "[%s] ReplayQueue::closed", to_string());
}
/**
* ReplayQueue accepts a NonblockingReportingSemaphore<bool> which, when signaled, returns
* true if the remote folder is ready and open, false if not (closing or closed), and
* throws an Error if the semaphore has failed. ReplayQueue will wait on this semaphore for
* each ReplayOperation waiting to perform a remote operation, cancelling it if the remote
* folder is not ready.
*/
public ReplayQueue(string name, NonblockingReportingSemaphore<bool> remote_reporting_semaphore) {
this.name = name;
this.remote_reporting_semaphore = remote_reporting_semaphore;
@ -293,21 +300,9 @@ private class Geary.ImapEngine.ReplayQueue {
}
private async void do_replay_remote_async() {
try {
if (!yield remote_reporting_semaphore.wait_for_result_async()) {
debug("Folder %s failed to open, remote replay queue closing", to_string());
return;
}
} catch (Error remote_err) {
debug("Error for remote queue waiting for remote %s to open, remote queue closing: %s", to_string(),
remote_err.message);
return;
}
bool queue_running = true;
while (queue_running) {
// wait for the next operation ... do this *before* waiting for remote
ReplayOperation op;
try {
op = yield remote_queue.recv_async();
@ -318,6 +313,20 @@ private class Geary.ImapEngine.ReplayQueue {
break;
}
// wait until the remote folder is opened (or returns false, in which case closed)
bool folder_opened = false;
try {
if (yield remote_reporting_semaphore.wait_for_result_async())
folder_opened = true;
else
debug("Folder %s closed or failed to open, remote replay queue closing", to_string());
} catch (Error remote_err) {
debug("Error for remote queue waiting for remote %s to open, remote queue closing: %s", to_string(),
remote_err.message);
// fall through
}
if (op is ReplayClose)
queue_running = false;
@ -325,13 +334,17 @@ private class Geary.ImapEngine.ReplayQueue {
ReplayOperation.Status status = ReplayOperation.Status.FAILED;
Error? remote_err = null;
try {
status = yield op.replay_remote_async();
} catch (Error replay_err) {
debug("Replay remote error for %s on %s: %s", op.to_string(), to_string(),
replay_err.message);
remote_err = replay_err;
if (folder_opened) {
try {
status = yield op.replay_remote_async();
} catch (Error replay_err) {
debug("Replay remote error for %s on %s: %s", op.to_string(), to_string(),
replay_err.message);
remote_err = replay_err;
}
} else {
remote_err = new EngineError.SERVER_UNAVAILABLE("Folder %s not available", to_string());
}
bool has_failed = (status == ReplayOperation.Status.FAILED);

View file

@ -138,6 +138,9 @@ public abstract class Geary.NonblockingAbstractSemaphore {
}
public virtual void reset() {
if (!passed)
return;
passed = false;
notify_at_reset();