[evolution-data-server] Bug 737468 - [IMAPx] Temporarily workaround 'Empty cache file' error
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug 737468 - [IMAPx] Temporarily workaround 'Empty cache file' error
- Date: Tue, 3 Mar 2015 17:36:46 +0000 (UTC)
commit 687d1b1bcba2f9a1a42f8c8e794cd17c1373f9c1
Author: Milan Crha <mcrha redhat com>
Date: Tue Mar 3 18:36:45 2015 +0100
Bug 737468 - [IMAPx] Temporarily workaround 'Empty cache file' error
camel/providers/imapx/camel-imapx-job.c | 24 ++++----
camel/providers/imapx/camel-imapx-server.c | 84 ++++++++++++++++++++++++----
camel/providers/imapx/camel-imapx-server.h | 2 +-
camel/providers/imapx/camel-imapx-store.c | 21 +++++++-
camel/providers/imapx/camel-imapx-store.h | 4 +
5 files changed, 109 insertions(+), 26 deletions(-)
---
diff --git a/camel/providers/imapx/camel-imapx-job.c b/camel/providers/imapx/camel-imapx-job.c
index 8f69b9f..7c79496 100644
--- a/camel/providers/imapx/camel-imapx-job.c
+++ b/camel/providers/imapx/camel-imapx-job.c
@@ -182,6 +182,7 @@ camel_imapx_job_wait (CamelIMAPXJob *job,
{
CamelIMAPXRealJob *real_job;
GCancellable *cancellable;
+ gulong cancel_id = 0;
gboolean success = TRUE;
g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
@@ -189,13 +190,23 @@ camel_imapx_job_wait (CamelIMAPXJob *job,
real_job = (CamelIMAPXRealJob *) job;
cancellable = camel_imapx_job_get_cancellable (job);
+ if (G_IS_CANCELLABLE (cancellable))
+ cancel_id = g_cancellable_connect (
+ cancellable,
+ G_CALLBACK (imapx_job_cancelled_cb),
+ camel_imapx_job_ref (job),
+ (GDestroyNotify) camel_imapx_job_unref);
+
g_mutex_lock (&real_job->done_mutex);
- while (!real_job->done_flag)
+ while (!real_job->done_flag && !g_cancellable_is_cancelled (cancellable))
g_cond_wait (
&real_job->done_cond,
&real_job->done_mutex);
g_mutex_unlock (&real_job->done_mutex);
+ if (cancel_id > 0)
+ g_cancellable_disconnect (cancellable, cancel_id);
+
/* Cancellation takes priority over other errors. */
if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
success = FALSE;
@@ -233,7 +244,6 @@ camel_imapx_job_run (CamelIMAPXJob *job,
GError **error)
{
GCancellable *cancellable;
- gulong cancel_id = 0;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
@@ -245,21 +255,11 @@ camel_imapx_job_run (CamelIMAPXJob *job,
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
- if (G_IS_CANCELLABLE (cancellable))
- cancel_id = g_cancellable_connect (
- cancellable,
- G_CALLBACK (imapx_job_cancelled_cb),
- camel_imapx_job_ref (job),
- (GDestroyNotify) camel_imapx_job_unref);
-
success = job->start (job, is, cancellable, error);
if (success && !job->noreply)
success = camel_imapx_job_wait (job, error);
- if (cancel_id > 0)
- g_cancellable_disconnect (cancellable, cancel_id);
-
return success;
}
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index cf5aa15..1d59f02 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -55,8 +55,27 @@
#define c(...) camel_imapx_debug(command, __VA_ARGS__)
#define e(...) camel_imapx_debug(extra, __VA_ARGS__)
-#define QUEUE_LOCK(x) (g_rec_mutex_lock(&(x)->queue_lock))
-#define QUEUE_UNLOCK(x) (g_rec_mutex_unlock(&(x)->queue_lock))
+#define QUEUE_LOCK(x) G_STMT_START { \
+ CamelIMAPXStore *imapx_store = camel_imapx_server_ref_store ((x)); \
+ \
+ if (imapx_store) { \
+ camel_imapx_store_job_queue_lock (imapx_store); \
+ g_object_unref (imapx_store); \
+ } \
+ \
+ g_rec_mutex_lock (&(x)->queue_lock); \
+ } G_STMT_END
+
+#define QUEUE_UNLOCK(x) G_STMT_START { \
+ CamelIMAPXStore *imapx_store = camel_imapx_server_ref_store ((x)); \
+ \
+ g_rec_mutex_unlock (&(x)->queue_lock); \
+ \
+ if (imapx_store) { \
+ camel_imapx_store_job_queue_unlock (imapx_store); \
+ g_object_unref (imapx_store); \
+ } \
+ } G_STMT_END
/* Try pipelining fetch requests, 'in bits' */
#define MULTI_SIZE (32768 * 8)
@@ -5162,23 +5181,54 @@ imapx_command_fetch_message_done (CamelIMAPXServer *is,
g_free (tmp_filename);
}
- /* Delete the 'tmp' file only if the operation wasn't cancelled. It's because
+ /* Delete the 'tmp' file only if the operation succeeded. It's because
cancelled operations end before they are properly finished (IMAP-protocol speaking),
thus if any other GET_MESSAGE operation was waiting for this job, then it
realized that the message was not downloaded and opened its own "tmp" file, but
of the same name, thus this remove would drop file which could be used
by a different GET_MESSAGE job. */
- if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ if (!local_error && !g_cancellable_is_cancelled (cancellable))
camel_data_cache_remove (data->message_cache, "tmp", data->uid, NULL);
/* Avoid possible use-after-free when the imapx_unregister_job() can
also free the 'job' structure. */
+ camel_imapx_job_ref (job);
+
+ imapx_unregister_job (is, job);
+
if (local_error != NULL) {
- camel_imapx_job_take_error (job, local_error);
- local_error = NULL;
+ CamelIMAPXJob *pending_job;
+
+ /* Give a chance to other threads. */
+ g_thread_yield ();
+
+ pending_job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, data->uid);
+ if (pending_job != NULL) {
+ GIOStream *cache_stream;
+
+ /* Wait for the job to finish. */
+ camel_imapx_job_wait (pending_job, NULL);
+ camel_imapx_job_unref (pending_job);
+
+ /* Disregard errors here. If we failed to retrieve the
+ * message from cache (implying the job we were waiting
+ * on failed or got cancelled), we'll just re-fetch it. */
+ cache_stream = camel_data_cache_get (data->message_cache, "cur", data->uid, NULL);
+ if (cache_stream != NULL) {
+ g_clear_error (&local_error);
+
+ g_clear_object (&data->stream);
+ data->stream = cache_stream;
+ }
+ }
+
+ if (local_error) {
+ camel_imapx_job_take_error (job, local_error);
+ local_error = NULL;
+ }
}
- imapx_unregister_job (is, job);
+ camel_imapx_job_unref (job);
exit:
if (local_error != NULL)
@@ -8313,9 +8363,7 @@ imapx_server_get_message (CamelIMAPXServer *is,
GetMessageData *data;
gboolean registered;
- job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, message_uid);
-
- if (job != NULL) {
+ while (job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, message_uid), job != NULL) {
/* Promote the existing GET_MESSAGE
* job's priority if ours is higher. */
if (pri > job->pri)
@@ -8331,14 +8379,26 @@ imapx_server_get_message (CamelIMAPXServer *is,
cache_stream = camel_data_cache_get (
message_cache, "cur", message_uid, NULL);
if (cache_stream != NULL) {
- stream = camel_stream_new (cache_stream);
+ /* Return new file stream, instead of a DataCache's to not fight
+ on its content and position with other jobs, if any. */
+ gchar *filename = camel_data_cache_get_filename (message_cache, "cur", message_uid);
+ stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL);
+ g_free (filename);
g_object_unref (cache_stream);
- return stream;
+
+ if (stream)
+ return stream;
}
}
QUEUE_LOCK (is);
+ if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ QUEUE_UNLOCK (is);
+
+ return NULL;
+ }
+
mi = camel_folder_summary_get (summary, message_uid);
if (mi == NULL) {
g_set_error (
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index 448b813..b7b876a 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -118,7 +118,7 @@ struct _CamelIMAPXServer {
/* Current command/work queue. All commands are stored in one list,
* all the time, so they can be cleaned up in exception cases */
- GRecMutex queue_lock;
+ GRecMutex queue_lock; /* use in combination with camel_imapx_store_job_queue_lock()/_unlock() */
CamelIMAPXCommand *literal;
CamelIMAPXCommandQueue *queue;
CamelIMAPXCommandQueue *active;
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index 8e21f49..13111b6 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -64,6 +64,8 @@ struct _CamelIMAPXStorePrivate {
CamelIMAPXServer *connecting_server;
gboolean is_concurrent_connection;
+ GRecMutex job_queue_lock;
+
GMutex server_lock;
GHashTable *quota_info;
@@ -703,8 +705,8 @@ imapx_store_finalize (GObject *object)
priv = CAMEL_IMAPX_STORE_GET_PRIVATE (object);
+ g_rec_mutex_clear (&priv->job_queue_lock);
g_mutex_clear (&priv->get_finfo_lock);
-
g_mutex_clear (&priv->server_lock);
g_hash_table_destroy (priv->quota_info);
@@ -2669,6 +2671,7 @@ camel_imapx_store_init (CamelIMAPXStore *store)
store->priv->con_man = camel_imapx_conn_manager_new (CAMEL_STORE (store));
+ g_rec_mutex_init (&store->priv->job_queue_lock);
g_mutex_init (&store->priv->get_finfo_lock);
g_mutex_init (&store->priv->namespaces_lock);
@@ -3463,6 +3466,22 @@ camel_imapx_store_ref_job (CamelIMAPXStore *imapx_store,
return job;
}
+void
+camel_imapx_store_job_queue_lock (CamelIMAPXStore *imapx_store)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store));
+
+ g_rec_mutex_lock (&imapx_store->priv->job_queue_lock);
+}
+
+void
+camel_imapx_store_job_queue_unlock (CamelIMAPXStore *imapx_store)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store));
+
+ g_rec_mutex_unlock (&imapx_store->priv->job_queue_lock);
+}
+
/* for debugging purposes only */
void
camel_imapx_store_dump_queue_status (CamelIMAPXStore *imapx_store)
diff --git a/camel/providers/imapx/camel-imapx-store.h b/camel/providers/imapx/camel-imapx-store.h
index f1311c2..b5e07d6 100644
--- a/camel/providers/imapx/camel-imapx-store.h
+++ b/camel/providers/imapx/camel-imapx-store.h
@@ -131,6 +131,10 @@ struct _CamelIMAPXJob *
CamelIMAPXMailbox *mailbox,
guint32 job_type,
const gchar *uid);
+void camel_imapx_store_job_queue_lock
+ (CamelIMAPXStore *imapx_store);
+void camel_imapx_store_job_queue_unlock
+ (CamelIMAPXStore *imapx_store);
/* for debugging purposes only */
void camel_imapx_store_dump_queue_status
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]