Do not hold references to all inode data in inode map.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Sun, 19 Sep 2010 00:44:07 +0000 (17:44 -0700)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Sun, 19 Sep 2010 00:44:07 +0000 (17:44 -0700)
The inode map should not hold full refereces to all inode objects and all
corresponding data, since that will lock all such data in memory or the
disk cache.  Do some initial work towards just holding weak references to
the data so that it can be expired from the cache.

bluesky/bluesky-private.h
bluesky/cache.c
bluesky/cloudlog.c
bluesky/imap.c

index 87237cc..fccc7a3 100644 (file)
@@ -288,9 +288,11 @@ 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_erase(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_insert_locked(BlueSkyCloudLog *log);
 BlueSkyCloudLog *bluesky_cloudlog_get(BlueSkyFS *fs, BlueSkyCloudID id);
 void bluesky_cloudlog_fetch(BlueSkyCloudLog *log);
 BlueSkyCloudPointer bluesky_cloudlog_serialize(BlueSkyCloudLog *log,
index c27d39d..3afceca 100644 (file)
@@ -107,7 +107,13 @@ static void flushd_dirty(BlueSkyFS *fs)
  * cloud.  When the write completes, we will allow old journal segments (those
  * that were fully written _before_ the snapshot process started) to be garbage
  * collected.  Newer journal segments can't be collected yet since they may
- * still contain data which has not been written persistently to the cloud. */
+ * still contain data which has not been written persistently to the cloud.
+ *
+ * Note that some of this code relies on the fact that only this thread of
+ * control (running flushd_cloud) is manipulating the inode map, and so
+ * concurrent updates to the inode map are prevented even without the
+ * filesystem lock held.  Take great care if allowing multi-threaded access to
+ * the inode map... */
 static void flushd_cloud(BlueSkyFS *fs)
 {
     g_mutex_lock(fs->lock);
@@ -150,13 +156,17 @@ static void flushd_cloud(BlueSkyFS *fs)
 
         g_mutex_lock(fs->lock);
     }
+    g_mutex_unlock(fs->lock);
 
     /* Write out any updated inode map entries, so that all inodes just written
      * can be located, and then a final commit record. */
     BlueSkyCloudLog *commit_record = bluesky_inode_map_serialize(fs);
-    bluesky_cloudlog_serialize(commit_record, fs);
+    if (commit_record != NULL) {
+        bluesky_cloudlog_serialize(commit_record, fs);
+    } else {
+        g_print("No need for a checkpoint record...\n");
+    }
 
-    g_mutex_unlock(fs->lock);
     bluesky_cloudlog_flush(fs);
 
     /* Wait until all segments have been written to the cloud, so that it
@@ -179,6 +189,7 @@ static void flushd_cloud(BlueSkyFS *fs)
     }
 
     bluesky_log_write_commit_point(fs, marker);
+    bluesky_cloudlog_unref(commit_record);
 
     g_print("All segments have been flushed, journal < %d is clean\n",
             journal_seq_start);
index c4cb1ae..5d14fc6 100644 (file)
@@ -165,6 +165,31 @@ void bluesky_cloudlog_unref(BlueSkyCloudLog *log)
     }
 }
 
+/* Erase the information contained within the in-memory cloud log
+ * representation.  This does not free up the item itself, but frees the data
+ * and references to other log items and resets the type back to unknown.  If
+ * the object was written out to persistent storage, all state about it can be
+ * recovered by loading the object back in.  The object must be locked before
+ * calling this function. */
+void bluesky_cloudlog_erase(BlueSkyCloudLog *log)
+{
+    g_assert(log->data_lock_count == 0);
+
+    log->type = LOGTYPE_UNKNOWN;
+    log->data_size = 0;
+    bluesky_string_unref(log->data);
+    log->data = NULL;
+    log->data_lock_count = 0;
+
+    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);
+    log->links = g_array_new(FALSE, TRUE, sizeof(BlueSkyCloudLog *));
+}
+
 /* Start a write of the object to the local log. */
 void bluesky_cloudlog_sync(BlueSkyCloudLog *log)
 {
@@ -173,10 +198,15 @@ void bluesky_cloudlog_sync(BlueSkyCloudLog *log)
 
 /* Add the given entry to the global hash table containing cloud log entries.
  * Takes ownership of the caller's reference. */
+void bluesky_cloudlog_insert_locked(BlueSkyCloudLog *log)
+{
+    g_hash_table_insert(log->fs->locations, &log->id, log);
+}
+
 void bluesky_cloudlog_insert(BlueSkyCloudLog *log)
 {
     g_mutex_lock(log->fs->lock);
-    g_hash_table_insert(log->fs->locations, &log->id, log);
+    bluesky_cloudlog_insert(log);
     g_mutex_unlock(log->fs->lock);
 }
 
@@ -317,6 +347,10 @@ BlueSkyCloudPointer bluesky_cloudlog_serialize(BlueSkyCloudLog *log,
 
     log->location.size = state->data->len - log->location.offset;
 
+    g_string_free(data1, TRUE);
+    g_string_free(data2, TRUE);
+    g_string_free(data3, TRUE);
+
     /* If the object we flushed was an inode, update the inode map. */
     if (log->type == LOGTYPE_INODE) {
         g_mutex_lock(fs->lock);
index cc8f1ba..5d5be8a 100644 (file)
@@ -156,6 +156,7 @@ static void bluesky_inode_map_serialize_section(BlueSkyFS *fs,
 
 BlueSkyCloudLog *bluesky_inode_map_serialize(BlueSkyFS *fs)
 {
+    gboolean updated = FALSE;
     GString *buf = g_string_new("");
     BlueSkyCloudLog *log = bluesky_cloudlog_new(fs, NULL);
     log->type = LOGTYPE_CHECKPOINT;
@@ -169,15 +170,23 @@ BlueSkyCloudLog *bluesky_inode_map_serialize(BlueSkyFS *fs)
         inum = GUINT64_TO_LE(range->end);
         g_string_append_len(buf, (const char *)&inum, sizeof(inum));
 
-        if (range->serialized == NULL)
+        if (range->serialized == NULL) {
             bluesky_inode_map_serialize_section(fs, range);
+            updated = TRUE;
+        }
         bluesky_cloudlog_ref(range->serialized);
         g_array_append_val(log->links, range->serialized);
         i = g_sequence_iter_next(i);
     }
 
     log->data = bluesky_string_new_from_gstring(buf);
-    return log;
+
+    if (updated) {
+        return log;
+    } else {
+        bluesky_cloudlog_unref(log);
+        return NULL;
+    }
 }
 
 /* Reconstruct the inode map from data stored in the cloud. */