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-data-cache.c | 140 ++++++++++++----------------------------------- 1 file changed, 35 insertions(+), 105 deletions(-) (limited to 'camel/camel-data-cache.c') diff --git a/camel/camel-data-cache.c b/camel/camel-data-cache.c index 6147a888f1..c0d399bbff 100644 --- a/camel/camel-data-cache.c +++ b/camel/camel-data-cache.c @@ -55,27 +55,17 @@ static void stream_finalised(CamelObject *o, void *event_data, void *data); #define CAMEL_DATA_CACHE_CYCLE_TIME (60*60) struct _CamelDataCachePrivate { - GHashTable *busy_stream; - GHashTable *busy_path; + CamelObjectBag *busy_bag; int expire_inc; time_t expire_last[1<priv->l) -#define CDC_UNLOCK(c, l) g_mutex_unlock(((CamelDataCache *)(c))->priv->l) -#else -#define CDC_LOCK(c, l) -#define CDC_UNLOCK(c, l) -#endif }; static CamelObject *camel_data_cache_parent; static void data_cache_class_init(CamelDataCacheClass *klass) { - camel_data_cache_parent = (CamelObject *)camel_type_get_global_classfuncs (camel_object_get_type ()); + camel_data_cache_parent = (CamelObject *)camel_object_get_type (); #if 0 klass->add = data_cache_add; @@ -91,39 +81,17 @@ static void data_cache_init(CamelDataCache *cdc, CamelDataCacheClass *klass) struct _CamelDataCachePrivate *p; p = cdc->priv = g_malloc0(sizeof(*cdc->priv)); - - p->busy_stream = g_hash_table_new(NULL, NULL); - p->busy_path = g_hash_table_new(g_str_hash, g_str_equal); - -#ifdef ENABLE_THREADS - p->lock = g_mutex_new(); -#endif -} - -static void -free_busy(CamelStream *stream, char *path, CamelDataCache *cdc) -{ - d(printf(" Freeing busy stream %p path %s\n", stream, path)); - camel_object_unhook_event((CamelObject *)stream, "finalize", stream_finalised, cdc); - camel_object_unref((CamelObject *)stream); - g_free(path); + p->busy_bag = camel_object_bag_new(g_str_hash, g_str_equal); } static void data_cache_finalise(CamelDataCache *cdc) { struct _CamelDataCachePrivate *p; + GPtrArray *streams; + int i; p = cdc->priv; - - d(printf("cache finalised, %d (= %d?) streams reamining\n", g_hash_table_size(p->busy_stream), g_hash_table_size(p->busy_path))); - - g_hash_table_foreach(p->busy_stream, (GHFunc)free_busy, cdc); - g_hash_table_destroy(p->busy_path); - g_hash_table_destroy(p->busy_stream); - -#ifdef ENABLE_THREADS - g_mutex_free(p->lock); -#endif + camel_object_bag_destroy(p->busy_bag); g_free(p); g_free (cdc->path); @@ -249,10 +217,10 @@ data_cache_expire(CamelDataCache *cdc, const char *path, const char *keep, time_ || (cdc->expire_access != -1 && st.st_atime + cdc->expire_access < now))) { dd(printf("Has expired! Removing!\n")); unlink(s->str); - if (g_hash_table_lookup_extended(cdc->priv->busy_path, s->str, (void **)&oldpath, (void **)&stream)) { - g_hash_table_remove(cdc->priv->busy_path, oldpath); - g_hash_table_remove(cdc->priv->busy_stream, stream); - g_free(oldpath); + stream = camel_object_bag_get(cdc->priv->busy_bag, s->str); + if (stream) { + camel_object_bag_remove(cdc->priv->busy_bag, stream); + camel_object_unref(stream); } } } @@ -283,10 +251,11 @@ data_cache_path(CamelDataCache *cdc, int create, const char *path, const char *k dd(printf("Checking expire cycle time on dir '%s'\n", dir)); + /* This has a race, but at worst we re-run an expire cycle which is safe */ now = time(0); if (cdc->priv->expire_last[hash] + CAMEL_DATA_CACHE_CYCLE_TIME < now) { - data_cache_expire(cdc, dir, key, now); cdc->priv->expire_last[hash] = now; + data_cache_expire(cdc, dir, key, now); } cdc->priv->expire_inc = (cdc->priv->expire_inc + 1) & CAMEL_DATA_CACHE_MASK; } @@ -298,27 +267,6 @@ data_cache_path(CamelDataCache *cdc, int create, const char *path, const char *k return real; } -static void -stream_finalised(CamelObject *o, void *event_data, void *data) -{ - CamelDataCache *cdc = data; - char *key; - - d(printf("Stream finalised '%p'\n", data)); - - CDC_LOCK(cdc, lock); - key = g_hash_table_lookup(cdc->priv->busy_stream, o); - if (key) { - d(printf(" For path '%s'\n", key)); - g_hash_table_remove(cdc->priv->busy_path, key); - g_hash_table_remove(cdc->priv->busy_stream, o); - g_free(key); - } else { - d(printf(" Unknown stream?!\n")); - } - CDC_UNLOCK(cdc, lock); -} - /** * camel_data_cache_add: * @cdc: @@ -340,29 +288,24 @@ stream_finalised(CamelObject *o, void *event_data, void *data) CamelStream * camel_data_cache_add(CamelDataCache *cdc, const char *path, const char *key, CamelException *ex) { - char *real, *oldpath; + char *real; CamelStream *stream; - CDC_LOCK(cdc, lock); - real = data_cache_path(cdc, TRUE, path, key); - if (g_hash_table_lookup_extended(cdc->priv->busy_path, real, (void **)&oldpath, (void **)&stream)) { - g_hash_table_remove(cdc->priv->busy_path, oldpath); - g_hash_table_remove(cdc->priv->busy_stream, stream); - unlink(oldpath); - g_free(oldpath); + stream = camel_object_bag_reserve(cdc->priv->busy_bag, real); + if (stream) { + unlink(real); + camel_object_bag_remove(cdc->priv->busy_bag, stream); + camel_object_unref(stream); } stream = camel_stream_fs_new_with_name(real, O_RDWR|O_CREAT|O_TRUNC, 0600); - if (stream) { - camel_object_hook_event((CamelObject *)stream, "finalize", stream_finalised, cdc); - g_hash_table_insert(cdc->priv->busy_stream, stream, real); - g_hash_table_insert(cdc->priv->busy_path, real, stream); - } else { - g_free(real); - } + if (stream) + camel_object_bag_add(cdc->priv->busy_bag, real, stream); + else + camel_object_bag_abort(cdc->priv->busy_bag, real); - CDC_UNLOCK(cdc, lock); + g_free(real); return stream; } @@ -387,25 +330,16 @@ camel_data_cache_get(CamelDataCache *cdc, const char *path, const char *key, Cam char *real; CamelStream *stream; - CDC_LOCK(cdc, lock); - real = data_cache_path(cdc, FALSE, path, key); - stream = g_hash_table_lookup(cdc->priv->busy_path, real); - if (stream) { - camel_object_ref((CamelObject *)stream); - g_free(real); - } else { + stream = camel_object_bag_reserve(cdc->priv->busy_bag, real); + if (!stream) { stream = camel_stream_fs_new_with_name(real, O_RDWR, 0600); - if (stream) { - camel_object_hook_event((CamelObject *)stream, "finalize", stream_finalised, cdc); - g_hash_table_insert(cdc->priv->busy_stream, stream, real); - g_hash_table_insert(cdc->priv->busy_path, real, stream); - } else { - g_free (real); - } + if (stream) + camel_object_bag_add(cdc->priv->busy_bag, real, stream); + else + camel_object_bag_abort(cdc->priv->busy_bag, real); } - - CDC_UNLOCK(cdc, lock); + g_free(real); return stream; } @@ -425,16 +359,14 @@ int camel_data_cache_remove(CamelDataCache *cdc, const char *path, const char *key, CamelException *ex) { CamelStream *stream; - char *real, *oldpath; + char *real; int ret; - CDC_LOCK(cdc, lock); - real = data_cache_path(cdc, FALSE, path, key); - if (g_hash_table_lookup_extended(cdc->priv->busy_path, real, (void **)&oldpath, (void **)&stream)) { - g_hash_table_remove(cdc->priv->busy_path, oldpath); - g_hash_table_remove(cdc->priv->busy_stream, stream); - g_free(oldpath); + stream = camel_object_bag_get(cdc->priv->busy_bag, real); + if (stream) { + camel_object_bag_remove(cdc->priv->busy_bag, stream); + camel_object_unref(stream); } /* maybe we were a mem stream */ @@ -449,8 +381,6 @@ camel_data_cache_remove(CamelDataCache *cdc, const char *path, const char *key, g_free(real); - CDC_UNLOCK(cdc, lock); - return ret; } -- cgit