From ac5113f4988176ca8b4f8f575df82ba7d05495cd Mon Sep 17 00:00:00 2001 From: Michael Vrable Date: Tue, 3 Aug 2010 21:58:51 -0700 Subject: [PATCH] Fix up reference counting for cloud log items. --- bluesky/cloudlog.c | 27 ++++++++++++++++++++++++++- bluesky/file.c | 7 ++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/bluesky/cloudlog.c b/bluesky/cloudlog.c index 1cae4a5..0d91e0d 100644 --- a/bluesky/cloudlog.c +++ b/bluesky/cloudlog.c @@ -97,6 +97,16 @@ BlueSkyCloudLog *bluesky_cloudlog_new(BlueSkyFS *fs) return log; } +/* The reference held by the hash table does not count towards the reference + * count. When a new object is created, it initially has a reference count of + * 1 for the creator, and similarly fetching an item from the hash table will + * also create a reference. If the reference count drops to zero, + * bluesky_cloudlog_unref attempts to remove the object from the hash + * table--but there is a potential race since another thread might read the + * object from the hash table at the same time. So an object with a reference + * count of zero may still be resurrected, in which case we need to abort the + * destruction. Once the object is gone from the hash table, and if the + * reference count is still zero, it can actually be deleted. */ void bluesky_cloudlog_ref(BlueSkyCloudLog *log) { if (log == NULL) @@ -111,7 +121,22 @@ void bluesky_cloudlog_unref(BlueSkyCloudLog *log) return; if (g_atomic_int_dec_and_test(&log->refcount)) { - g_print("Cloud log refcount dropped to zero.\n"); + BlueSkyFS *fs = log->fs; + + g_mutex_lock(fs->lock); + if (g_atomic_int_get(&log->refcount) > 0) { + g_mutex_unlock(fs->lock); + return; + } + + g_hash_table_remove(fs->locations, &log->id); + g_mutex_unlock(fs->lock); + + g_mutex_free(log->lock); + g_cond_free(log->cond); + g_array_unref(log->pointers); + bluesky_string_unref(log->data); + g_free(log); } } diff --git a/bluesky/file.c b/bluesky/file.c index 57193dd..b329531 100644 --- a/bluesky/file.c +++ b/bluesky/file.c @@ -50,8 +50,7 @@ void bluesky_block_touch(BlueSkyInode *inode, uint64_t i) g_atomic_int_add(&inode->fs->cache_dirty, 1); block->type = BLUESKY_BLOCK_DIRTY; - if (block->cloudref != NULL) - bluesky_cloudlog_unref(block->cloudref); + bluesky_cloudlog_unref(block->cloudref); block->cloudref = NULL; } @@ -243,8 +242,7 @@ void bluesky_block_flush(BlueSkyInode *inode, BlueSkyBlock *block, if (block->type != BLUESKY_BLOCK_DIRTY) return; - if (block->cloudref != NULL) - bluesky_cloudlog_unref(block->cloudref); + bluesky_cloudlog_unref(block->cloudref); BlueSkyRCStr *data = block->data; @@ -258,7 +256,6 @@ void bluesky_block_flush(BlueSkyInode *inode, BlueSkyBlock *block, bluesky_cloudlog_insert(cloudlog); block->cloudref = cloudlog; - bluesky_cloudlog_ref(cloudlog); block->type = BLUESKY_BLOCK_CACHED; g_atomic_int_add(&fs->cache_dirty, -1); -- 2.20.1