From 24b06cb2a4030282763c8f60ba3b0b8b806d15d3 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Mon, 9 Dec 2002 00:28:06 +0000 Subject: Use a bag instead of a hashtable to track the cache streams. 2002-12-07 Not Zed * camel-data-cache.c (data_cache_init): Use a bag instead of a hashtable to track the cache streams. (data_cache_finalise): Same. (free_busy): No longer needed. (data_cache_expire): use bag instead of hashtable. (stream_finalised): No longer required. (camel_data_cache_add): objectbagise (camel_data_cache_get): " (camel_data_cache_remove): " (data_cache_path): Set the now expired date before running expiry, so it plays better with multiple threads. Still a couple of harmless races. 2002-12-06 Not Zed * providers/local/camel-spool-store.c (scan_dir): folders -> object bag. (get_folder_info_mbox): folders -> object bag. * providers/local/camel-mh-store.c (folder_info_new): folders -> object bag. * providers/local/camel-maildir-store.c (scan_dir): folders -> object bag. * providers/local/camel-local-store.c (rename_folder): folders -> object bag. * camel-private.h (CamelStorePrivate): Remove 'cache' lock, handled by the objectbag. * providers/imap/camel-imap-store.c (copy_folder): Removed. (imap_store_refresh_folders): folders -> object bag. (get_folder_counts): folders -> object bag. * camel-vee-store.c (vee_get_folder): changes for folders objectbag. (vee_get_folder_info): Change to use folders objectbag. Also, dont refresh the base folder if we're in FAST mode. (build_info): Removed, no longer needed. (vee_rename_folder): Fixed for folders objectbag. * camel-store.c (camel_store_init): init the folders objectbag. (camel_store_finalize): Destroy the folders object bag. (folder_matches): (folder_finalize): Removed, now handled implicitly by the objectbag. (camel_store_get_folder): object bag changes. (camel_store_delete_folder): " (get_subfolders): Removed, now handled without a callback. (camel_store_rename_folder): Changed to use object bag of folders. (trash_add_folder): Removed. (init_trash): use folders object bag. (copy_folder_cache): (sync_folder): Removed, no longer needed. Weird arsed code anyway. (store_sync): Use folder object bag instead of hashtable. (camel_store_unsubscribe_folder): " (camel_store_init): remove cache_lock init, no longer used. (camel_store_finalize): Same for cleanup. 2002-12-05 Not Zed * camel-store.h (struct _CamelStore): change folders from a hashtable into a CamelObjectBag. * camel-object.c (camel_object_ref): Use type_lock instead of class lock for ref counting. (camel_object_unref): Use type_lock instead of class lock for unref. (camel_object_unref): If the object is 'bagged', then also look hooks, and remove it from any bags. (camel_object_bag_new): (camel_object_bag_destroy): (camel_object_bag_add): (camel_object_bag_get): (camel_object_bag_remove_unlocked): (camel_object_bag_list): (camel_object_bag_abort): (camel_object_bag_remove): New functions to implement a utility object which can manage a 'bag' of weakly ref'd children in an atomic & threadsafe way. svn path=/trunk/; revision=19056 --- camel/camel-store.c | 254 ++++++++++++++++------------------------------------ 1 file changed, 75 insertions(+), 179 deletions(-) (limited to 'camel/camel-store.c') diff --git a/camel/camel-store.c b/camel/camel-store.c index d76af40e60..c6454fc8f5 100644 --- a/camel/camel-store.c +++ b/camel/camel-store.c @@ -126,8 +126,8 @@ camel_store_init (void *o) CamelStoreClass *store_class = (CamelStoreClass *)CAMEL_OBJECT_GET_CLASS (o); if (store_class->hash_folder_name) { - store->folders = g_hash_table_new (store_class->hash_folder_name, - store_class->compare_folder_name); + store->folders = camel_object_bag_new(store_class->hash_folder_name, + store_class->compare_folder_name); } else store->folders = NULL; @@ -139,7 +139,6 @@ camel_store_init (void *o) store->priv = g_malloc0 (sizeof (*store->priv)); #ifdef ENABLE_THREADS store->priv->folder_lock = e_mutex_new (E_MUTEX_REC); - store->priv->cache_lock = e_mutex_new (E_MUTEX_SIMPLE); #endif } @@ -148,18 +147,11 @@ camel_store_finalize (CamelObject *object) { CamelStore *store = CAMEL_STORE (object); - if (store->folders) { - if (g_hash_table_size (store->folders) != 0) { - d(g_warning ("Folder cache for store %p contains " - "%d folders at destruction.", store, - g_hash_table_size (store->folders))); - } - g_hash_table_destroy (store->folders); - } + if (store->folders) + camel_object_bag_destroy(store->folders); #ifdef ENABLE_THREADS e_mutex_destroy (store->priv->folder_lock); - e_mutex_destroy (store->priv->cache_lock); #endif g_free (store->priv); } @@ -197,28 +189,6 @@ store_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args) return CAMEL_OBJECT_CLASS (parent_class)->getv (object, ex, args); } -static gboolean -folder_matches (gpointer key, gpointer value, gpointer user_data) -{ - if (value == user_data) { - g_free (key); - return TRUE; - } else - return FALSE; -} - -static void -folder_finalize (CamelObject *folder, gpointer event_data, gpointer user_data) -{ - CamelStore *store = CAMEL_STORE (user_data); - - if (store->folders) { - CAMEL_STORE_LOCK(store, cache_lock); - g_hash_table_foreach_remove (store->folders, folder_matches, folder); - CAMEL_STORE_UNLOCK(store, cache_lock); - } -} - static void construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, @@ -264,14 +234,9 @@ camel_store_get_folder (CamelStore *store, const char *folder_name, guint32 flag CAMEL_STORE_LOCK(store, folder_lock); - if (store->folders) { + if (store->folders) /* Try cache first. */ - CAMEL_STORE_LOCK(store, cache_lock); - folder = g_hash_table_lookup (store->folders, folder_name); - if (folder) - camel_object_ref (CAMEL_OBJECT (folder)); - CAMEL_STORE_UNLOCK(store, cache_lock); - } + folder = camel_object_bag_reserve(store->folders, folder_name); if (!folder) { folder = CS_CLASS (store)->get_folder (store, folder_name, flags, ex); @@ -280,17 +245,14 @@ camel_store_get_folder (CamelStore *store, const char *folder_name, guint32 flag if (store->vtrash) camel_vee_folder_add_folder (CAMEL_VEE_FOLDER (store->vtrash), folder); - if (store->folders) { - CAMEL_STORE_LOCK(store, cache_lock); - - g_hash_table_insert (store->folders, g_strdup (folder_name), folder); - - camel_object_hook_event (CAMEL_OBJECT (folder), "finalize", folder_finalize, store); - CAMEL_STORE_UNLOCK(store, cache_lock); - } + if (store->folders) + camel_object_bag_add(store->folders, folder_name, folder); + } else { + if (store->folders) + camel_object_bag_abort(store->folders, folder_name); } } - + CAMEL_STORE_UNLOCK(store, folder_lock); return folder; } @@ -362,12 +324,7 @@ camel_store_delete_folder (CamelStore *store, const char *folder_name, CamelExce /* if we deleted a folder, force it out of the cache, and also out of the vtrash if setup */ if (store->folders) { - CAMEL_STORE_LOCK(store, cache_lock); - folder = g_hash_table_lookup(store->folders, folder_name); - if (folder) - camel_object_ref((CamelObject *)folder); - CAMEL_STORE_UNLOCK(store, cache_lock); - + folder = camel_object_bag_get(store->folders, folder_name); if (folder) { if (store->vtrash) camel_vee_folder_remove_folder((CamelVeeFolder *)store->vtrash, folder); @@ -377,17 +334,11 @@ camel_store_delete_folder (CamelStore *store, const char *folder_name, CamelExce CS_CLASS (store)->delete_folder (store, folder_name, ex); - if (folder) - camel_object_unref((CamelObject *)folder); + if (store->folders) + camel_object_bag_remove(store->folders, folder); - if (store->folders) { - CAMEL_STORE_LOCK(store, cache_lock); - if (g_hash_table_lookup_extended(store->folders, folder_name, (void **)&key, (void **)&folder)) { - g_hash_table_remove (store->folders, key); - g_free (key); - } - CAMEL_STORE_UNLOCK(store, cache_lock); - } + if (folder) + camel_object_unref(folder); CAMEL_STORE_UNLOCK(store, folder_lock); } @@ -399,34 +350,6 @@ rename_folder (CamelStore *store, const char *old_name, const char *new_name, Ca camel_type_to_name (CAMEL_OBJECT_GET_TYPE (store)))); } -struct _get_info { - CamelStore *store; - GPtrArray *folders; - const char *old; - const char *new; -}; - -static void -get_subfolders(char *key, CamelFolder *folder, struct _get_info *info) -{ - int oldlen, namelen; - - namelen = strlen(folder->full_name); - oldlen = strlen(info->old); - - if ((namelen == oldlen && - strcmp(folder->full_name, info->old) == 0) - || ((namelen > oldlen) - && strncmp(folder->full_name, info->old, oldlen) == 0 - && folder->full_name[oldlen] == info->store->dir_sep)) { - - d(printf("Found subfolder of '%s' == '%s'\n", info->old, folder->full_name)); - camel_object_ref((CamelObject *)folder); - g_ptr_array_add(info->folders, folder); - CAMEL_FOLDER_LOCK(folder, lock); - } -} - /** * camel_store_rename_folder: * @store: a CamelStore @@ -440,26 +363,39 @@ void camel_store_rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex) { char *key; - CamelFolder *folder, *oldfolder; - struct _get_info info = { store, NULL, old_name, new_name }; - int i; + CamelFolder *folder; + int i, oldlen, namelen; + GPtrArray *folders; d(printf("store rename folder %s '%s' '%s'\n", ((CamelService *)store)->url->protocol, old_name, new_name)); if (strcmp(old_name, new_name) == 0) return; - info.folders = g_ptr_array_new(); + oldlen = strlen(old_name); CAMEL_STORE_LOCK(store, folder_lock); /* If the folder is open (or any subfolders of the open folder) We need to rename them atomically with renaming the actual folder path */ if (store->folders) { - CAMEL_STORE_LOCK(store, cache_lock); - /* Get all subfolders that are about to have their name changed */ - g_hash_table_foreach(store->folders, (GHFunc)get_subfolders, &info); - CAMEL_STORE_UNLOCK(store, cache_lock); + folders = camel_object_bag_list(store->folders); + for (i=0;ilen;i++) { + folder = folders->pdata[i]; + namelen = strlen(folder->full_name); + if ((namelen == oldlen && + strcmp(folder->full_name, old_name) == 0) + || ((namelen > oldlen) + && strncmp(folder->full_name, old_name, oldlen) == 0 + && folder->full_name[oldlen] == store->dir_sep)) { + d(printf("Found subfolder of '%s' == '%s'\n", old_name, folder->full_name)); + CAMEL_FOLDER_LOCK(folder, lock); + } else { + g_ptr_array_remove_index_fast(folders, i); + i--; + camel_object_unref(folder); + } + } } /* Now try the real rename (will emit renamed event) */ @@ -470,26 +406,19 @@ camel_store_rename_folder (CamelStore *store, const char *old_name, const char * guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE; CamelRenameInfo reninfo; - CAMEL_STORE_LOCK(store, cache_lock); - for (i=0;ilen;i++) { + for (i=0;ilen;i++) { char *new; - folder = info.folders->pdata[i]; + folder = folders->pdata[i]; new = g_strdup_printf("%s%s", new_name, folder->full_name+strlen(old_name)); - - if (g_hash_table_lookup_extended(store->folders, folder->full_name, (void **)&key, (void **)&oldfolder)) { - g_hash_table_remove(store->folders, key); - g_free(key); - g_hash_table_insert(store->folders, new, oldfolder); - } - + camel_object_bag_remove(store->folders, folder); + camel_object_bag_add(store->folders, new, folder); camel_folder_rename(folder, new); CAMEL_FOLDER_UNLOCK(folder, lock); - camel_object_unref((CamelObject *)folder); + camel_object_unref(folder); } - CAMEL_STORE_UNLOCK(store, cache_lock); /* Emit changed signal */ if (store->flags & CAMEL_STORE_SUBSCRIPTIONS) @@ -503,16 +432,16 @@ camel_store_rename_folder (CamelStore *store, const char *old_name, const char * } } else { /* Failed, just unlock our folders for re-use */ - for (i=0;ilen;i++) { - folder = info.folders->pdata[i]; + for (i=0;ilen;i++) { + folder = folders->pdata[i]; CAMEL_FOLDER_UNLOCK(folder, lock); - camel_object_unref((CamelObject *)folder); + camel_object_unref(folder); } } CAMEL_STORE_UNLOCK(store, folder_lock); - g_ptr_array_free(info.folders, TRUE); + g_ptr_array_free(folders, TRUE); } @@ -545,16 +474,6 @@ camel_store_get_inbox (CamelStore *store, CamelException *ex) return folder; } - -static void -trash_add_folder (gpointer key, gpointer value, gpointer data) -{ - CamelFolder *folder = CAMEL_FOLDER (value); - CamelStore *store = CAMEL_STORE (data); - - camel_vee_folder_add_folder (CAMEL_VEE_FOLDER (store->vtrash), folder); -} - static void trash_finalize (CamelObject *trash, gpointer event_data, gpointer user_data) { @@ -572,15 +491,21 @@ init_trash (CamelStore *store) store->vtrash = camel_vtrash_folder_new (store, CAMEL_VTRASH_NAME); if (store->vtrash) { + /* FIXME: this should probably use the object bag or another one ? ... */ /* attach to the finalise event of the vtrash */ camel_object_hook_event (CAMEL_OBJECT (store->vtrash), "finalize", trash_finalize, store); /* add all the pre-opened folders to the vtrash */ if (store->folders) { - CAMEL_STORE_LOCK(store, cache_lock); - g_hash_table_foreach (store->folders, trash_add_folder, store); - CAMEL_STORE_UNLOCK(store, cache_lock); + GPtrArray *folders = camel_object_bag_list(store->folders); + int i; + + for (i=0;ilen;i++) { + camel_vee_folder_add_folder (CAMEL_VEE_FOLDER (store->vtrash), (CamelFolder *)folders->pdata[i]); + camel_object_unref(folders->pdata[i]); + } + g_ptr_array_free(folders, TRUE); } } } @@ -629,42 +554,24 @@ camel_store_get_trash (CamelStore *store, CamelException *ex) return folder; } - -static void -sync_folder (gpointer key, gpointer folder, gpointer ex) -{ - if (!camel_exception_is_set (ex)) - camel_folder_sync (folder, FALSE, ex); - - camel_object_unref (CAMEL_OBJECT (folder)); - g_free (key); -} - -static void -copy_folder_cache (gpointer key, gpointer folder, gpointer hash) -{ - g_hash_table_insert ((GHashTable *) hash, g_strdup (key), folder); - camel_object_ref (CAMEL_OBJECT (folder)); -} - static void store_sync (CamelStore *store, CamelException *ex) { if (store->folders) { - CamelException internal_ex; - GHashTable *hash; - - hash = g_hash_table_new (CS_CLASS (store)->hash_folder_name, - CS_CLASS (store)->compare_folder_name); - - camel_exception_init (&internal_ex); - CAMEL_STORE_LOCK(store, cache_lock); - g_hash_table_foreach (store->folders, copy_folder_cache, hash); - CAMEL_STORE_UNLOCK(store, cache_lock); - camel_exception_xfer (ex, &internal_ex); - - g_hash_table_foreach (hash, sync_folder, &internal_ex); - g_hash_table_destroy (hash); + GPtrArray *folders; + CamelFolder *folder; + CamelException x; + int i; + + folders = camel_object_bag_list(store->folders); + for (i=0;ilen;i++) { + folder = folders->pdata[i]; + if (!camel_exception_is_set(&x)) + camel_folder_sync(folder, FALSE, &x); + camel_object_unref(folder); + } + camel_exception_xfer(ex, &x); + g_ptr_array_free(folders, TRUE); } } @@ -1102,12 +1009,7 @@ camel_store_unsubscribe_folder (CamelStore *store, /* if we deleted a folder, force it out of the cache, and also out of the vtrash if setup */ if (store->folders) { - CAMEL_STORE_LOCK(store, cache_lock); - folder = g_hash_table_lookup(store->folders, folder_name); - if (folder) - camel_object_ref((CamelObject *)folder); - CAMEL_STORE_UNLOCK(store, cache_lock); - + folder = camel_object_bag_get(store->folders, folder_name); if (folder) { if (store->vtrash) camel_vee_folder_remove_folder((CamelVeeFolder *)store->vtrash, folder); @@ -1117,17 +1019,11 @@ camel_store_unsubscribe_folder (CamelStore *store, CS_CLASS (store)->unsubscribe_folder (store, folder_name, ex); - if (folder) - camel_object_unref((CamelObject *)folder); + if (store->folders) + camel_object_bag_remove(store->folders, folder); - if (store->folders) { - CAMEL_STORE_LOCK(store, cache_lock); - if (g_hash_table_lookup_extended(store->folders, folder_name, (void **)&key, (void **)&folder)) { - g_hash_table_remove (store->folders, key); - g_free (key); - } - CAMEL_STORE_UNLOCK(store, cache_lock); - } + if (folder) + camel_object_unref(folder); CAMEL_STORE_UNLOCK(store, folder_lock); } -- cgit v1.2.3