BlueSkyCryptKeys *keys);
void bluesky_cloudlog_encrypt(GString *segment, BlueSkyCryptKeys *keys);
void bluesky_cloudlog_decrypt(char *segment, size_t len,
- BlueSkyCryptKeys *keys);
+ BlueSkyCryptKeys *keys,
+ BlueSkyRangeset *items);
/* Storage layer. Requests can be performed asynchronously, so these objects
* help keep track of operations in progress. */
BlueSkyLog *log;
gboolean fetching, ready; // Cloud data: downloading or ready for use
int64_t atime; // Access time, for cache management
+ BlueSkyRangeset *items; // Locations of valid items
};
BlueSkyLog *bluesky_log_new(const char *log_directory);
BlueSkyRCStr *bluesky_string_dup(BlueSkyRCStr *string);
void bluesky_string_resize(BlueSkyRCStr *string, gsize len);
+struct BlueSkyRangeset;
+typedef struct BlueSkyRangeset BlueSkyRangeset;
+BlueSkyRangeset *bluesky_rangeset_new();
+void bluesky_rangeset_free(BlueSkyRangeset *rangeset);
+gboolean bluesky_rangeset_insert(BlueSkyRangeset *rangeset,
+ int start, int length, gpointer data);
+gpointer bluesky_rangeset_lookup(BlueSkyRangeset *rangeset, int start);
+
/* Storage interface. This presents a key-value store abstraction, and can
* have multiple implementations: in-memory, on-disk, in-cloud. */
struct BlueSkyStore;
g_atomic_int_add(&fs->log->disk_used, -(cachefile->len / 1024));
g_hash_table_remove(fs->log->mmap_cache, cachefile->filename);
+ bluesky_rangeset_free(cachefile->items);
g_mutex_unlock(cachefile->lock);
g_mutex_free(cachefile->lock);
g_cond_free(cachefile->cond);
}
/* Make an decryption pass over a cloud log segment to decrypt items which were
- * encrypted. TODO: Also computes a list of all offsets which at which valid
- * cloud log items are found. */
-void bluesky_cloudlog_decrypt(char *segment, size_t len, BlueSkyCryptKeys *keys)
+ * encrypted. Also computes a list of all offsets which at which valid
+ * cloud log items are found and adds those offsets to items (if non-NULL). */
+void bluesky_cloudlog_decrypt(char *segment, size_t len,
+ BlueSkyCryptKeys *keys,
+ BlueSkyRangeset *items)
{
char *data = segment;
size_t remaining_size = len;
+ size_t offset = 0;
while (remaining_size >= sizeof(struct cloudlog_header)) {
struct cloudlog_header *header = (struct cloudlog_header *)data;
if (item_size > remaining_size)
break;
if (bluesky_crypt_block_decrypt(data, item_size, keys)) {
- /* TODO: Mark block as valid. */
+ if (items != NULL) {
+ g_print(" data item at %zx\n", offset);
+ bluesky_rangeset_insert(items, offset, item_size,
+ GINT_TO_POINTER(TRUE));
+ }
+ } else {
+ g_warning("Unauthenticated data at offset %zd", offset);
+ if (items != NULL) {
+ bluesky_rangeset_insert(items, offset, item_size,
+ GINT_TO_POINTER(TRUE));
+ }
}
data += item_size;
+ offset += item_size;
remaining_size -= item_size;
}
}
}
last = bluesky_string_dup(last);
- bluesky_cloudlog_decrypt(last->data, last->len, fs->keys);
+ bluesky_cloudlog_decrypt(last->data, last->len, fs->keys, NULL);
/* 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
cachefile->filename);
async->data = bluesky_string_dup(async->data);
bluesky_cloudlog_decrypt(async->data->data, async->data->len,
- cachefile->fs->keys);
+ cachefile->fs->keys, cachefile->items);
if (!g_file_set_contents(pathname, async->data->data, async->data->len,
NULL))
g_print("Error writing out fetched file to cache!\n");
map->log = log;
g_atomic_int_set(&map->mapcount, 0);
g_atomic_int_set(&map->refcount, 0);
+ map->items = bluesky_rangeset_new();
g_hash_table_insert(log->mmap_cache, map->filename, map);
return NULL;
}
+ /* Log segments fetched from the cloud might only be partially-fetched.
+ * Check whether the object we are interested in is available. */
+ if (log_dir >= 0) {
+ if (!bluesky_rangeset_lookup(map->items, log_offset)) {
+ g_warning("log-%d: Item at offset %d does not seem to be available\n", log_seq, log_offset);
+ }
+ }
+
if (map->addr == NULL) {
while (!map->ready && map->fetching) {
g_print("Waiting for log segment to be fetched from cloud...\n");
else
return (BlueSkyInode *)head->prev->data;
}
+
+/**** Range sets. ****/
+
+/* These are a data structure which can track a set of discontiguous integer
+ * ranges--such as the partitioning of the inode number space or the bytes in a
+ * log file into objects. This current prototype implementation just tracks
+ * the starting offset with a hash table and doesn't track the length, but
+ * should be extended later to track properly. */
+
+struct BlueSkyRangeset {
+ GHashTable *hashtable;
+};
+
+BlueSkyRangeset *bluesky_rangeset_new()
+{
+ BlueSkyRangeset *rangeset = g_new(BlueSkyRangeset, 1);
+ rangeset->hashtable = g_hash_table_new(g_direct_hash, g_direct_equal);
+ return rangeset;
+}
+
+void bluesky_rangeset_free(BlueSkyRangeset *rangeset)
+{
+ g_hash_table_unref(rangeset->hashtable);
+ g_free(rangeset);
+}
+
+gboolean bluesky_rangeset_insert(BlueSkyRangeset *rangeset,
+ int start, int length, gpointer data)
+{
+ g_hash_table_insert(rangeset->hashtable, GINT_TO_POINTER(start), data);
+ return TRUE;
+}
+
+gpointer bluesky_rangeset_lookup(BlueSkyRangeset *rangeset, int start)
+{
+ return g_hash_table_lookup(rangeset->hashtable, GINT_TO_POINTER(start));
+}