log->fs = fs;
log->type = LOGTYPE_UNKNOWN;
log->id = bluesky_cloudlog_new_id();
- log->pointers = g_array_new(FALSE, TRUE, sizeof(BlueSkyCloudID));
+ log->links = g_array_new(FALSE, TRUE, sizeof(BlueSkyCloudLog *));
g_atomic_int_set(&log->refcount, 1);
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);
+
+ log->type = LOGTYPE_INVALID;
+ g_mutex_free(log->lock);
+ g_cond_free(log->cond);
+ for (int i = 0; i < log->links->len; i++) {
+ BlueSkyCloudLog *c = g_array_index(log->links,
+ BlueSkyCloudLog *, i);
+ bluesky_cloudlog_unref(c);
+ }
+ g_array_unref(log->links);
+ bluesky_string_unref(log->data);
+ g_free(log);
}
}
return log->location;
}
- g_print("Flushing object %s to cloud...\n",
- bluesky_cloudlog_id_to_string(log->id));
-
- for (int i = 0; i < log->pointers->len; i++) {
- BlueSkyCloudID id = g_array_index(log->pointers, BlueSkyCloudID, i);
- g_print(" ...checking reference %s...\n",
- bluesky_cloudlog_id_to_string(id));
- g_mutex_lock(log->fs->lock);
- BlueSkyCloudLog *log2
- = (BlueSkyCloudLog *)g_hash_table_lookup(log->fs->locations, &id);
- // TODO: refcount
- g_assert(log2 != NULL);
- bluesky_cloudlog_ref(log2);
- g_mutex_unlock(log->fs->lock);
- bluesky_cloudlog_serialize(log2, state);
- bluesky_cloudlog_unref(log2);
+ for (int i = 0; i < log->links->len; i++) {
+ BlueSkyCloudLog *ref = g_array_index(log->links,
+ BlueSkyCloudLog *, i);
+ if (ref != NULL)
+ bluesky_cloudlog_serialize(ref, state);
}
g_mutex_lock(log->lock);
while (state->inode_list != NULL) {
BlueSkyCloudLog *log = (BlueSkyCloudLog *)state->inode_list->data;
bluesky_cloudlog_serialize(log, state);
+ bluesky_cloudlog_unref(log);
state->inode_list = g_list_delete_link(state->inode_list,
state->inode_list);
}
state->location.sequence++;
state->location.offset = 0;
+ } else {
+ g_string_free(state->data, TRUE);
}
state->data = NULL;