Improve tracking of memory usage in BlueSky.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Wed, 11 Aug 2010 19:29:09 +0000 (12:29 -0700)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Wed, 11 Aug 2010 19:29:09 +0000 (12:29 -0700)
Most data, except for dirty data blocks not flushed out to the journal yet,
will be in the form of cloud log entries.  Create statistics counters to
track how many cloud log items are in each of several states (in memory
only, writeback, on disk, in cloud).

bluesky/bluesky-private.h
bluesky/bluesky.h
bluesky/cache.c
bluesky/cloudlog.c
bluesky/debug.c
bluesky/file.c
bluesky/log.c
bluesky/serialize.c

index bc3df37..643092b 100644 (file)
@@ -233,6 +233,7 @@ gchar *bluesky_cloudlog_id_to_string(BlueSkyCloudID id);
 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);
index e9e40d8..099aad4 100644 (file)
@@ -143,10 +143,19 @@ typedef struct {
     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
index d4d410e..9287c97 100644 (file)
@@ -217,14 +217,13 @@ void bluesky_flushd_invoke(BlueSkyFS *fs)
 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);
index 4c671be..6e57d05 100644 (file)
@@ -93,6 +93,25 @@ BlueSkyCloudLog *bluesky_cloudlog_new(BlueSkyFS *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
@@ -128,6 +147,7 @@ void bluesky_cloudlog_unref(BlueSkyCloudLog *log)
         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);
@@ -184,8 +204,10 @@ void bluesky_cloudlog_fetch(BlueSkyCloudLog *log)
 
     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);
 }
@@ -210,6 +232,8 @@ BlueSkyCloudPointer bluesky_cloudlog_serialize(BlueSkyCloudLog *log,
     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
@@ -226,6 +250,7 @@ BlueSkyCloudPointer bluesky_cloudlog_serialize(BlueSkyCloudLog *log,
     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)
index 6242ba6..43b29be 100644 (file)
@@ -55,11 +55,14 @@ static void cloudlog_dump(gpointer key, gpointer value, gpointer user_data)
 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:");
index d3ba5f8..94677f6 100644 (file)
@@ -44,8 +44,6 @@ void bluesky_block_touch(BlueSkyInode *inode, uint64_t i)
         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);
 
@@ -97,9 +95,6 @@ void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size)
         /* 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);
@@ -233,7 +228,6 @@ void bluesky_block_fetch(BlueSkyInode *inode, BlueSkyBlock *block,
     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. */
@@ -251,6 +245,7 @@ void bluesky_block_flush(BlueSkyInode *inode, BlueSkyBlock *block,
     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);
@@ -287,11 +282,12 @@ void bluesky_file_drop_cached(BlueSkyInode *inode)
                 && 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);
         }
     }
 }
index 9dfaa5b..c45ffc8 100644 (file)
@@ -77,8 +77,10 @@ static void log_commit(BlueSkyLog *log)
     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);
@@ -158,7 +160,9 @@ static gpointer log_thread(gpointer d)
             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;
index da9aa97..6eef425 100644 (file)
@@ -147,6 +147,7 @@ BlueSkyCloudLog *bluesky_serialize_inode(BlueSkyInode *inode)
 
     cloudlog->data = bluesky_string_new_from_gstring(out);
     bluesky_cloudlog_insert(cloudlog);
+    bluesky_cloudlog_stats_update(cloudlog, 1);
 
     return cloudlog;
 }