Fix up reference counting for cloud log items.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Wed, 4 Aug 2010 04:58:51 +0000 (21:58 -0700)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Wed, 4 Aug 2010 04:58:51 +0000 (21:58 -0700)
bluesky/cloudlog.c
bluesky/file.c

index 1cae4a5..0d91e0d 100644 (file)
@@ -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);
     }
 }
 
index 57193dd..b329531 100644 (file)
@@ -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);