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)
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);
}
}
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;
}
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;
bluesky_cloudlog_insert(cloudlog);
block->cloudref = cloudlog;
- bluesky_cloudlog_ref(cloudlog);
block->type = BLUESKY_BLOCK_CACHED;
g_atomic_int_add(&fs->cache_dirty, -1);