X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=bluesky%2Fcloudlog.c;h=30c2db0f947f1f15f6b2249d166c8d5c5d1e7f09;hb=bf5f9f2e43078f7d31858be259b9c60a8c08a096;hp=1cae4a5b0bde591bedde5e4650a2a9d6bf21e596;hpb=ed6f1f04bd4d7a73ed26b3bb0d5e0df1cc0acf42;p=bluesky.git diff --git a/bluesky/cloudlog.c b/bluesky/cloudlog.c index 1cae4a5..30c2db0 100644 --- a/bluesky/cloudlog.c +++ b/bluesky/cloudlog.c @@ -91,12 +91,22 @@ BlueSkyCloudLog *bluesky_cloudlog_new(BlueSkyFS *fs) 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) @@ -111,7 +121,28 @@ 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); + + 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); } } @@ -157,19 +188,11 @@ BlueSkyCloudPointer bluesky_cloudlog_serialize(BlueSkyCloudLog *log, 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); @@ -222,6 +245,7 @@ void bluesky_cloudlog_write_log(BlueSkyFS *fs) 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); }