X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=bluesky%2Fimap.c;h=0cdf9c56255dd88b31fafaba68891b05e7ced1f6;hb=56b93c6854c139faa9de04f6907eb586acd3e6ec;hp=484f24f57a740979d0cf26bd486bdc73e252e728;hpb=2b3dd7b15178288761500a6896376b4d44d3bfae;p=bluesky.git diff --git a/bluesky/imap.c b/bluesky/imap.c index 484f24f..0cdf9c5 100644 --- a/bluesky/imap.c +++ b/bluesky/imap.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -178,3 +179,108 @@ BlueSkyCloudLog *bluesky_inode_map_serialize(BlueSkyFS *fs) log->data = bluesky_string_new_from_gstring(buf); return log; } + +/* Reconstruct the inode map from data stored in the cloud. */ +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 *, i); + 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); + + 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; +}