BlueSkyCloudID bluesky_cloudlog_id_from_string(const gchar *idstr);
void bluesky_cloudlog_ref(BlueSkyCloudLog *log);
void bluesky_cloudlog_unref(BlueSkyCloudLog *log);
+void bluesky_cloudlog_stats_update(BlueSkyCloudLog *log, int type);
void bluesky_cloudlog_sync(BlueSkyCloudLog *log);
void bluesky_cloudlog_insert(BlueSkyCloudLog *log);
void bluesky_cloudlog_fetch(BlueSkyCloudLog *log);
BlueSkyCloudLogState *log_state;
/* Accounting for memory used for caches. Space is measured in blocks, not
- * bytes. We track both total data in the caches and dirty data (total
- * data includes dirty data). Updates to these variables must be made
- * atomically. */
- gint cache_total, cache_dirty;
+ * bytes. Updates to these variables must be made atomically. */
+ gint cache_dirty;
+
+ /* Like above, but tracking data stored in the cloudlog entries
+ * specifically:
+ * - cache_log_dirty: data uncommitted to journal and cloud
+ * - cache_log_writeback: data being written to journal
+ * - cache_log_journal: data committed to journal
+ * - cache_log_cloud: data written to cloud as well
+ * Log entries should progress from the top state to the bottom, and are
+ * only ever counted in one category at a time. */
+ gint cache_log_dirty, cache_log_writeback,
+ cache_log_journal, cache_log_cloud;
/* Linked list of inodes, sorted by access/modification times for cache
* management. Editing these lists is protected by the filesystem lock; to
void bluesky_flushd_invoke_conditional(BlueSkyFS *fs)
{
if (g_atomic_int_get(&fs->cache_dirty) < bluesky_watermark_high_dirty
- && g_atomic_int_get(&fs->cache_total) < bluesky_watermark_high_total)
+ /*&& g_atomic_int_get(&fs->cache_total) < bluesky_watermark_high_total*/)
return;
if (bluesky_verbose) {
g_log("bluesky/flushd", G_LOG_LEVEL_DEBUG,
- "Too much data; invoking flushd: dirty=%d total=%d",
- g_atomic_int_get(&fs->cache_dirty),
- g_atomic_int_get(&fs->cache_total));
+ "Too much data; invoking flushd: dirty=%d",
+ g_atomic_int_get(&fs->cache_dirty));
}
bluesky_flushd_invoke(fs);
return log;
}
+/* Helper function for updating memory usage statistics for a filesystem (the
+ * cache_log_* variables). This will increment (type=1) or decrement (type=-1)
+ * the counter associated with the current state of the cloud log item. The
+ * item should be locked or otherwise protected from concurrent access. */
+void bluesky_cloudlog_stats_update(BlueSkyCloudLog *log, int type)
+{
+ BlueSkyFS *fs = log->fs;
+
+ if (log->location_flags & CLOUDLOG_CLOUD) {
+ g_atomic_int_add(&fs->cache_log_cloud, type);
+ } else if (log->location_flags & CLOUDLOG_JOURNAL) {
+ g_atomic_int_add(&fs->cache_log_journal, type);
+ } else if (log->pending_write & CLOUDLOG_JOURNAL) {
+ g_atomic_int_add(&fs->cache_log_journal, type);
+ } else if (log->data != NULL) {
+ g_atomic_int_add(&fs->cache_log_dirty, type);
+ }
+}
+
/* 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
g_hash_table_remove(fs->locations, &log->id);
g_mutex_unlock(fs->lock);
+ bluesky_cloudlog_stats_update(log, -1);
log->type = LOGTYPE_INVALID;
g_mutex_free(log->lock);
g_cond_free(log->cond);
g_assert((log->location_flags | log->pending_write) & CLOUDLOG_JOURNAL);
+ bluesky_cloudlog_stats_update(log, -1);
log->data = bluesky_log_map_object(log->fs->log, log->log_seq,
log->log_offset, log->log_size);
+ bluesky_cloudlog_stats_update(log, 1);
g_cond_broadcast(log->cond);
}
bluesky_cloudlog_fetch(log);
g_assert(log->data != NULL);
+ bluesky_cloudlog_stats_update(log, -1);
+
log->location = state->location;
log->location.offset = state->data->len;
log->location.size
g_string_append_len(state->data, log->data->data, log->data->len);
log->location_flags |= CLOUDLOG_CLOUD;
+ bluesky_cloudlog_stats_update(log, 1);
g_mutex_unlock(log->lock);
if (state->data->len > CLOUDLOG_SEGMENT_SIZE)
void bluesky_debug_dump(BlueSkyFS *fs)
{
g_print("*** DEBUG DUMP FOR FILESYSTEM %s ***\n", fs->name);
- g_print("Cached blocks: %d\tDirty blocks: %d\n",
- g_atomic_int_get(&fs->cache_total),
- g_atomic_int_get(&fs->cache_dirty));
+ g_print("Dirty blocks: %d\n", g_atomic_int_get(&fs->cache_dirty));
g_print("Cached inodes: %u\tNext inode: %"PRIu64"\n",
g_hash_table_size(fs->inodes), fs->next_inum);
+ g_print("Cloudlog cache: %d dirty, %d writeback, %d journal, %d cloud\n",
+ g_atomic_int_get(&fs->cache_log_dirty),
+ g_atomic_int_get(&fs->cache_log_writeback),
+ g_atomic_int_get(&fs->cache_log_journal),
+ g_atomic_int_get(&fs->cache_log_cloud));
GList *item;
g_print("Unsynced inode list:");
break;
}
- if (block->type != BLUESKY_BLOCK_REF && block->type != BLUESKY_BLOCK_DIRTY)
- g_atomic_int_add(&inode->fs->cache_total, 1);
if (block->type != BLUESKY_BLOCK_DIRTY)
g_atomic_int_add(&inode->fs->cache_dirty, 1);
/* Delete blocks from a file. Must reclaim memory. */
for (guint i = inode->blocks->len; i < blocks; i++) {
BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, i);
- if (b->type == BLUESKY_BLOCK_REF
- || b->type == BLUESKY_BLOCK_DIRTY)
- g_atomic_int_add(&inode->fs->cache_total, -1);
if (b->type == BLUESKY_BLOCK_DIRTY)
g_atomic_int_add(&inode->fs->cache_dirty, -1);
bluesky_string_unref(b->dirty);
bluesky_cloudlog_fetch(block->ref);
g_mutex_unlock(block->ref->lock);
block->type = BLUESKY_BLOCK_REF;
- g_atomic_int_add(&inode->fs->cache_total, 1); //FIXME
}
/* Write the given block to cloud-backed storage and mark it clean. */
cloudlog->type = LOGTYPE_DATA;
cloudlog->inum = inode->inum;
cloudlog->data = block->dirty; // String ownership is transferred
+ bluesky_cloudlog_stats_update(cloudlog, 1);
bluesky_cloudlog_sync(cloudlog);
bluesky_cloudlog_ref(cloudlog); // Reference for log_items list
*log_items = g_list_prepend(*log_items, cloudlog);
&& g_atomic_int_get(&b->ref->data_lock_count) == 0
&& (b->ref->location_flags != 0))
{
+ bluesky_cloudlog_stats_update(b->ref, -1);
bluesky_string_unref(b->ref->data);
b->ref->data = NULL;
+ bluesky_cloudlog_stats_update(b->ref, 1);
}
g_mutex_unlock(b->ref->lock);
- g_atomic_int_add(&inode->fs->cache_total, -1);
}
}
}
while (log->committed != NULL) {
BlueSkyCloudLog *item = (BlueSkyCloudLog *)log->committed->data;
g_mutex_lock(item->lock);
+ bluesky_cloudlog_stats_update(item, -1);
item->pending_write &= ~CLOUDLOG_JOURNAL;
item->location_flags |= CLOUDLOG_JOURNAL;
+ bluesky_cloudlog_stats_update(item, 1);
g_cond_signal(item->cond);
g_mutex_unlock(item->lock);
log->committed = g_slist_delete_link(log->committed, log->committed);
continue;
}
+ bluesky_cloudlog_stats_update(item, -1);
item->pending_write |= CLOUDLOG_JOURNAL;
+ bluesky_cloudlog_stats_update(item, 1);
struct log_header header;
struct log_footer footer;
cloudlog->data = bluesky_string_new_from_gstring(out);
bluesky_cloudlog_insert(cloudlog);
+ bluesky_cloudlog_stats_update(cloudlog, 1);
return cloudlog;
}