X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=bluesky%2Fimap.c;h=a3d27caea6f3166c737a71e44be879c557cab064;hb=0f7a0642cd1b9d98af851b9cf2ed14c9a83ddfc2;hp=dc24b58209c1802046405c154cf9bb3208e27c0a;hpb=2ad1881ef34f84f3dc8ded636ada9b21e3fd906b;p=bluesky.git diff --git a/bluesky/imap.c b/bluesky/imap.c index dc24b58..a3d27ca 100644 --- a/bluesky/imap.c +++ b/bluesky/imap.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -180,10 +181,107 @@ BlueSkyCloudLog *bluesky_inode_map_serialize(BlueSkyFS *fs) } /* Reconstruct the inode map from data stored in the cloud. */ -void bluesky_inode_map_deserialize(BlueSkyFS *fs, BlueSkyCloudLog *imap) +static void bluesky_inode_map_deserialize(BlueSkyFS *fs, BlueSkyCloudLog *imap) { g_mutex_lock(imap->lock); bluesky_cloudlog_fetch(imap); g_assert(imap->data != NULL); + g_assert(imap->data->len == 16 * imap->links->len); + //uint64_t *inum_range = (uint64_t *)imap->data->data; + for (int i = 0; i < imap->links->len; i++) { + //int64_t start = GUINT64_FROM_LE(*inum_range++); + //int64_t end = GUINT64_FROM_LE(*inum_range++); + BlueSkyCloudLog *section = g_array_index(imap->links, + BlueSkyCloudLog *, i); + g_mutex_lock(section->lock); + bluesky_cloudlog_fetch(section); + g_print("Loaded cloudlog item (%zd bytes)\n", section->data->len); + + uint64_t *inum = (uint64_t *)section->data->data; + for (int j = 0; j < section->links->len; j++) { + InodeMapEntry *entry; + entry = bluesky_inode_map_lookup(fs->inode_map, *inum, 1); + entry->inum = *inum; + entry->item = g_array_index(section->links, + BlueSkyCloudLog *, j); + bluesky_cloudlog_ref(entry->item); + entry->id = entry->item->id; + entry->location = entry->item->location; + inum++; + } + g_mutex_unlock(section->lock); + } g_mutex_unlock(imap->lock); } + +/* Find the most recent checkpoint record in the cloud and reload inode map + * data from it to initialize the filesystem. Returns a boolean indicating + * whether a checkpoint was found and loaded or not. */ +gboolean bluesky_checkpoint_load(BlueSkyFS *fs) +{ + char *last_segment = bluesky_store_lookup_last(fs->store, "log-"); + if (last_segment == NULL) + return FALSE; + + g_print("Last cloud log segment: %s\n", last_segment); + int seq = atoi(last_segment + 13); + fs->log_state->location.sequence = seq + 1; + + BlueSkyRCStr *last = bluesky_store_get(fs->store, last_segment); + g_free(last_segment); + if (last == NULL) { + g_warning("Unable to fetch last log segment from cloud!"); + return FALSE; + } + + /* Scan through the contents of the last log segment to find a checkpoint + * record. We need to do a linear scan since at this point we don't have a + * direct pointer; once we have the last commit record then all other data + * can be loaded by directly following pointers. */ + const char *buf = last->data; + size_t len = last->len; + const char *checkpoint = NULL; + size_t checkpoint_size = 0; + while (len > sizeof(struct cloudlog_header)) { + struct cloudlog_header *header = (struct cloudlog_header *)buf; + if (memcmp(header->magic, CLOUDLOG_MAGIC, 4) != 0) { + g_warning("Could not parse cloudlog entry!"); + break; + } + int size = sizeof(struct cloudlog_header); + size += GUINT32_FROM_LE(header->size1); + size += GUINT32_FROM_LE(header->size2); + size += GUINT32_FROM_LE(header->size3); + if (size > len) { + g_warning("Cloudlog entry is malformed (size too large)!"); + break; + } + if (header->type - '0' == LOGTYPE_CHECKPOINT) { + checkpoint = buf; + checkpoint_size = size; + } + buf += size; + len -= size; + } + + g_print("Found checkpoint record at %zd (size %zd)\n", + checkpoint - last->data, checkpoint_size); + + /* Bootstrap the loading process by manually setting the location of this + * log item. */ + BlueSkyCloudLog *commit; + commit = bluesky_cloudlog_get(fs, + ((struct cloudlog_header *)checkpoint)->id); + g_mutex_lock(commit->lock); + commit->location_flags |= CLOUDLOG_CLOUD; + commit->location.directory = 0; + commit->location.sequence = seq; + commit->location.offset = checkpoint - last->data; + commit->location.size = checkpoint_size; + g_mutex_unlock(commit->lock); + + bluesky_inode_map_deserialize(fs, commit); + //bluesky_cloudlog_unref(commit); + + return TRUE; +}