gchar *bluesky_lowercase(const gchar *s);
-/* Reference-counted blocks of memory, used for passing data in and out of
- * storage backends and in other places. */
+struct _BlueSkyCacheFile;
+typedef struct _BlueSkyCacheFile BlueSkyCacheFile;
+
typedef struct {
gint refcount;
+ BlueSkyCacheFile *mmap;
gchar *data;
gsize len;
} BlueSkyRCStr;
BlueSkyRCStr *bluesky_string_new(gpointer data, gsize len);
BlueSkyRCStr *bluesky_string_new_from_gstring(GString *s);
+BlueSkyRCStr *bluesky_string_new_from_mmap(BlueSkyCacheFile *mmap,
+ int offset, gsize len);
void bluesky_string_ref(BlueSkyRCStr *string);
void bluesky_string_unref(BlueSkyRCStr *string);
BlueSkyRCStr *bluesky_string_dup(BlueSkyRCStr *string);
struct _BlueSkyStore;
typedef struct _BlueSkyStore BlueSkyStore;
+struct _BlueSkyLog;
+typedef struct _BlueSkyLog BlueSkyLog;
+
+struct _BlueSkyCloudLogState;
+typedef struct _BlueSkyCloudLogState BlueSkyCloudLogState;
+
+struct _BlueSkyCloudLog;
+typedef struct _BlueSkyCloudLog BlueSkyCloudLog;
+
void bluesky_store_init();
BlueSkyStore *bluesky_store_new(const gchar *type);
void bluesky_store_free(BlueSkyStore *store);
uint64_t next_inum; /* Next available inode for allocation */
BlueSkyStore *store;
+ BlueSkyLog *log;
+ 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
* avoid deadlock do not attempt to take any other locks while the FS lock
* is held for list editing purposes. Items at the head of the list are
* most recently accessed/modified. */
- GList dirty_list, accessed_list;
+ GList unlogged_list; // Changes not yet synced to journal
+ GList dirty_list; // Not yet written to cloud storage
+ GList accessed_list; // All in-memory inodes
/* Mutex for the flush daemon, to prevent concurrent execution. */
GMutex *flushd_lock;
+
+ /* Used to wait for the cache daemon to free up space */
+ GCond *flushd_cond;
+
+ /* Mapping of object identifiers (blocks, inodes) to physical location (in
+ * the local cache or in the logs in the cloud). */
+ GHashTable *locations;
} BlueSkyFS;
/* Inode number of the root directory. */
/* change_count is increased with every operation which modifies the inode,
* and can be used to determine if cached data is still valid.
* change_commit is the value of change_count when the inode was last
- * committed to stable storage. */
- uint64_t change_count, change_commit;
+ * committed to stable storage (the log).
+ * change_cloud tracks which version was last commited to cloud storage. */
+ uint64_t change_count, change_commit, change_cloud;
/* Timestamp for controlling when modified data is flushed to stable
* storage. When an inode is first modified from a clean state, this is
/* Last access time to this inode, for controlling cache evictions. */
int64_t access_time;
- /* Additional state for tracking cache writeback status. */
- uint64_t change_pending; /* change_count version currently being committed to storage */
+ /* Version of the object last serialized and committed to storage. */
+ BlueSkyCloudLog *committed_item;
/* Pointers to the linked-list elements for this inode in the accessed and
* dirty linked lists. We re-use the GList structure, using ->next to
* point to the head of the list and ->prev to point to the tail. The data
* element is unused. */
- GList *accessed_list, *dirty_list;
+ GList *unlogged_list, *accessed_list, *dirty_list;
int64_t atime; /* Microseconds since the Unix epoch */
int64_t ctime;
#define BLUESKY_MAX_FILE_SIZE (BLUESKY_BLOCK_SIZE << 24)
typedef enum {
BLUESKY_BLOCK_ZERO = 0, /* Data is all zeroes, not explicitly stored */
- BLUESKY_BLOCK_REF = 1, /* Reference to key/value store, not cached */
- BLUESKY_BLOCK_CACHED = 2, /* Data is cached in memory, clean */
- BLUESKY_BLOCK_DIRTY = 3, /* Data needs to be committed to store */
+ BLUESKY_BLOCK_REF = 1, /* Reference to cloud log item, data clean */
+ BLUESKY_BLOCK_DIRTY = 2, /* Data needs to be committed to store */
} BlueSkyBlockType;
typedef struct {
BlueSkyBlockType type;
- gchar *ref; /* Name of data block in the backing store */
- BlueSkyRCStr *data; /* Pointer to data in memory if cached */
+ BlueSkyCloudLog *ref; /* if REF: cloud log entry with data */
+ BlueSkyRCStr *dirty; /* if DIRTY: raw data in memory */
} BlueSkyBlock;
BlueSkyFS *bluesky_init_fs(gchar *name, BlueSkyStore *store);
void bluesky_file_read(BlueSkyInode *inode, uint64_t offset,
char *buf, gint len);
-void bluesky_inode_flush(BlueSkyFS *fs, BlueSkyInode *inode);
void bluesky_inode_fetch(BlueSkyFS *fs, uint64_t inum);
gint bluesky_dirent_compare(gconstpointer a, gconstpointer b,