[evolution-data-server] Bug #646898 - IMAPX should invalidated cache when uidvalidity changes



commit 621d4e0acf20729ed889e6266458f2bce27ff42f
Author: Milan Crha <mcrha redhat com>
Date:   Tue May 17 11:30:38 2011 +0200

    Bug #646898 - IMAPX should invalidated cache when uidvalidity changes

 camel/camel-data-cache.c                   |   73 ++++++++++++++++++++++------
 camel/camel-data-cache.h                   |    2 +
 camel/providers/imapx/camel-imapx-server.c |   56 ++++++++++++++++++++--
 3 files changed, 112 insertions(+), 19 deletions(-)
---
diff --git a/camel/camel-data-cache.c b/camel/camel-data-cache.c
index e3ecd5f..57029e6 100644
--- a/camel/camel-data-cache.c
+++ b/camel/camel-data-cache.c
@@ -265,11 +265,10 @@ camel_data_cache_set_expire_access (CamelDataCache *cdc, time_t when)
 }
 
 static void
-data_cache_expire (CamelDataCache *cdc, const gchar *path, const gchar *keep, time_t now)
+data_cache_expire (CamelDataCache *cdc, const gchar *path, const gchar *keep, time_t now, gboolean expire_all)
 {
 	GDir *dir;
 	const gchar *dname;
-	GString *s;
 	struct stat st;
 	CamelStream *stream;
 
@@ -277,25 +276,29 @@ data_cache_expire (CamelDataCache *cdc, const gchar *path, const gchar *keep, ti
 	if (dir == NULL)
 		return;
 
-	s = g_string_new("");
 	while ((dname = g_dir_read_name (dir))) {
-		if (strcmp (dname, keep) == 0)
+		gchar *dpath;
+
+		if (keep && strcmp (dname, keep) == 0)
 			continue;
 
-		g_string_printf (s, "%s/%s", path, dname);
-		if (g_stat (s->str, &st) == 0
+		dpath = g_build_filename (path, dname, NULL);
+
+		if (g_stat (dpath, &st) == 0
 		    && S_ISREG (st.st_mode)
-		    && ((cdc->priv->expire_age != -1 && st.st_mtime + cdc->priv->expire_age < now)
+		    && (expire_all
+		        || (cdc->priv->expire_age != -1 && st.st_mtime + cdc->priv->expire_age < now)
 			|| (cdc->priv->expire_access != -1 && st.st_atime + cdc->priv->expire_access < now))) {
-			g_unlink (s->str);
-			stream = camel_object_bag_get (cdc->priv->busy_bag, s->str);
+			g_unlink (dpath);
+			stream = camel_object_bag_get (cdc->priv->busy_bag, dpath);
 			if (stream) {
 				camel_object_bag_remove (cdc->priv->busy_bag, stream);
 				g_object_unref (stream);
 			}
 		}
+
+		g_free (dpath);
 	}
-	g_string_free (s, TRUE);
 	g_dir_close (dir);
 }
 
@@ -314,11 +317,7 @@ data_cache_path (CamelDataCache *cdc, gint create, const gchar *path, const gcha
 	dir = alloca (strlen (cdc->priv->path) + strlen (path) + 8);
 	sprintf(dir, "%s/%s/%02x", cdc->priv->path, path, hash);
 
-#ifdef G_OS_WIN32
 	if (g_access (dir, F_OK) == -1) {
-#else
-	if (access (dir, F_OK) == -1) {
-#endif
 		if (create)
 			g_mkdir_with_parents (dir, 0700);
 	} else if (cdc->priv->expire_age != -1 || cdc->priv->expire_access != -1) {
@@ -328,7 +327,7 @@ data_cache_path (CamelDataCache *cdc, gint create, const gchar *path, const gcha
 		now = time (NULL);
 		if (cdc->priv->expire_last[hash] + CAMEL_DATA_CACHE_CYCLE_TIME < now) {
 			cdc->priv->expire_last[hash] = now;
-			data_cache_expire (cdc, dir, key, now);
+			data_cache_expire (cdc, dir, key, now, FALSE);
 		}
 	}
 
@@ -505,3 +504,47 @@ camel_data_cache_remove (CamelDataCache *cdc,
 	return ret;
 }
 
+/**
+ * camel_data_cache_clear:
+ * @cdc: a #CamelDataCache
+ * @path: Path to the (sub) cache the item exists in.
+ *
+ * Clear cache's content in @path.
+ **/
+void
+camel_data_cache_clear (CamelDataCache *cdc, const gchar *path)
+{
+	gchar *base_dir;
+	GDir *dir;
+	const gchar *dname;
+	struct stat st;
+
+	g_return_if_fail (cdc != NULL);
+	g_return_if_fail (path != NULL);
+
+	base_dir = g_build_filename (cdc->priv->path, path, NULL);
+
+	dir = g_dir_open (base_dir, 0, NULL);
+	if (dir == NULL) {
+		g_free (base_dir);
+		return;
+	}
+
+	while ((dname = g_dir_read_name (dir))) {
+		gchar *dpath;
+
+		dpath = g_build_filename (base_dir, dname, NULL);
+
+		if (g_stat (dpath, &st) == 0
+		    && S_ISDIR (st.st_mode)
+		    && !g_str_equal (dname, ".")
+		    && !g_str_equal (dname, "..")) {
+			data_cache_expire (cdc, dpath, NULL, -1, TRUE);
+		}
+
+		g_free (dpath);
+	}
+
+	g_dir_close (dir);
+	g_free (base_dir);
+}
diff --git a/camel/camel-data-cache.h b/camel/camel-data-cache.h
index 559b8b0..8b3e454 100644
--- a/camel/camel-data-cache.h
+++ b/camel/camel-data-cache.h
@@ -90,6 +90,8 @@ gchar *		camel_data_cache_get_filename	(CamelDataCache *cdc,
 						 const gchar *path,
 						 const gchar *key,
 						 GError **error);
+void		camel_data_cache_clear		(CamelDataCache *cdc,
+						 const gchar *path);
 
 G_END_DECLS
 
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 79157e7..c4640f7 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -1236,6 +1236,43 @@ imapx_expunge_uid_from_summary (CamelIMAPXServer *imap, gchar *uid, gboolean uns
 	}
 }
 
+static void
+invalidate_local_cache (CamelIMAPXFolder *ifolder, guint64 new_uidvalidity)
+{
+	CamelFolder *cfolder;
+	CamelFolderChangeInfo *changes;
+	GPtrArray *uids;
+	gint ii;
+
+	g_return_if_fail (ifolder != NULL);
+
+	cfolder = CAMEL_FOLDER (ifolder);
+	g_return_if_fail (cfolder != NULL);
+
+	changes = camel_folder_change_info_new ();
+
+	uids = camel_folder_summary_array (cfolder->summary);
+	for (ii = 0; uids && ii < uids->len; ii++) {
+		const gchar *uid = uids->pdata[ii];
+
+		if (uid)
+			camel_folder_change_info_change_uid (changes, uid);
+	}
+
+	g_ptr_array_foreach (uids, (GFunc) camel_pstring_free, NULL);
+	g_ptr_array_free (uids, TRUE);
+
+	CAMEL_IMAPX_SUMMARY (cfolder->summary)->validity = new_uidvalidity;
+	camel_folder_summary_touch (cfolder->summary);
+	camel_folder_summary_save_to_db (cfolder->summary, NULL);
+
+	camel_data_cache_clear (ifolder->cache, "cache");
+	camel_data_cache_clear (ifolder->cache, "cur");
+
+	camel_folder_changed (cfolder, changes);
+	camel_folder_change_info_free (changes);
+}
+
 /* handle any untagged responses */
 static gint
 imapx_untagged (CamelIMAPXServer *imap,
@@ -1637,11 +1674,15 @@ imapx_untagged (CamelIMAPXServer *imap,
 				}
 			}
 			if (ifolder) {
+				CamelFolder *cfolder = CAMEL_FOLDER (ifolder);
+
 				ifolder->unread_on_server = sinfo->unseen;
 				ifolder->exists_on_server = sinfo->messages;
 				ifolder->modseq_on_server = sinfo->highestmodseq;
 				ifolder->uidnext_on_server = sinfo->uidnext;
 				ifolder->uidvalidity_on_server = sinfo->uidvalidity;
+				if (sinfo->uidvalidity && sinfo->uidvalidity != ((CamelIMAPXSummary *) cfolder->summary)->validity)
+					invalidate_local_cache (ifolder, sinfo->uidvalidity);
 			} else {
 				c(imap->tagprefix, "Received STATUS for unknown folder '%s'\n", sinfo->name);
 			}
@@ -2491,6 +2532,8 @@ imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
 		is->state = IMAPX_INITIALISED;
 	} else {
 		CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) is->select_pending;
+		CamelFolder *cfolder = is->select_pending;
+
 		c(is->tagprefix, "Select ok!\n");
 
 		if (!is->select_folder) {
@@ -2508,11 +2551,11 @@ imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
 		}
 		ifolder->uidvalidity_on_server = is->uidvalidity;
 		selected_folder = camel_folder_get_full_name (is->select_folder);
-#if 0
-		/* This must trigger a complete index rebuild! */
-		if (is->uidvalidity && is->uidvalidity != ((CamelIMAPXSummary *) is->select_folder->summary)->uidvalidity)
-			g_warning("uidvalidity doesn't match!");
 
+		if (is->uidvalidity && is->uidvalidity != ((CamelIMAPXSummary *) cfolder->summary)->validity)
+			invalidate_local_cache (ifolder, is->uidvalidity);
+
+#if 0
 		/* This should trigger a new messages scan */
 		if (is->exists != is->select_folder->summary->root_view->total_count)
 			g_warning("exists is %d our summary is %d and summary exists is %d\n", is->exists,
@@ -4078,6 +4121,11 @@ imapx_job_refresh_info_start (CamelIMAPXServer *is,
 #endif
 	total = camel_folder_summary_count (folder->summary);
 
+	if (ifolder->uidvalidity_on_server && isum->validity && isum->validity != ifolder->uidvalidity_on_server) {
+		invalidate_local_cache (ifolder, ifolder->uidvalidity_on_server);
+		need_rescan = TRUE;
+	}
+
 	/* We don't have valid unread count or modseq for currently-selected server
 	   (unless we want to re-SELECT it). We fake unread count when fetching
 	   message flags, but don't depend on modseq for the selected folder */



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