1 /* Blue Sky: File Systems in the Cloud
3 * Copyright (C) 2009 The Regents of the University of California
4 * Written by Michael Vrable <mvrable@cs.ucsd.edu>
14 #include "bluesky-private.h"
16 /* Core filesystem: handling of regular files and caching of file data. */
18 /* Mark a given block dirty and make sure that data is faulted in so that it
19 * can be written to. */
20 void bluesky_block_touch(BlueSkyInode *inode, uint64_t i)
22 g_return_if_fail(i < inode->blocks->len);
23 BlueSkyBlock *block = &g_array_index(inode->blocks, BlueSkyBlock, i);
26 if (i < inode->blocks->len - 1) {
27 block_len = BLUESKY_BLOCK_SIZE;
29 block_len = inode->size - i * BLUESKY_BLOCK_SIZE;
32 switch (block->type) {
33 case BLUESKY_BLOCK_ZERO:
34 g_print("Allocating zero block of size %zd\n", block_len);
35 block->data = bluesky_string_new(g_malloc0(block_len), block_len);
37 case BLUESKY_BLOCK_REF:
38 bluesky_block_fetch(inode->fs, block);
39 g_assert(block->type == BLUESKY_BLOCK_CACHED);
41 case BLUESKY_BLOCK_CACHED:
42 case BLUESKY_BLOCK_DIRTY:
43 block->data = bluesky_string_dup(block->data);
47 block->type = BLUESKY_BLOCK_DIRTY;
50 /* Set the size of a file. This will truncate or extend the file as needed.
51 * Newly-allocated bytes are zeroed. */
52 void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size)
54 g_return_if_fail(size <= BLUESKY_MAX_FILE_SIZE);
56 if (size == inode->size)
59 g_print("Truncating file to %"PRIi64" bytes\n", size);
61 uint64_t blocks = (size + BLUESKY_BLOCK_SIZE - 1) / BLUESKY_BLOCK_SIZE;
63 if (blocks > inode->blocks->len) {
64 /* Need to add new blocks to the end of a file. New block structures
65 * are automatically zeroed, which initializes them to be pointers to
66 * zero blocks so we don't need to do any more work. If the
67 * previously-last block in the file is smaller than
68 * BLUESKY_BLOCK_SIZE, extend it to full size. */
69 if (inode->blocks->len > 0) {
70 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
71 inode->blocks->len - 1);
73 if (b->type != BLUESKY_BLOCK_ZERO
74 && b->data->len < BLUESKY_BLOCK_SIZE) {
75 bluesky_block_touch(inode, inode->blocks->len - 1);
76 gsize old_size = b->data->len;
77 bluesky_string_resize(b->data, BLUESKY_BLOCK_SIZE);
78 memset(&b->data->data[old_size], 0,
79 BLUESKY_BLOCK_SIZE - old_size);
83 g_array_set_size(inode->blocks, blocks);
84 } else if (blocks < inode->blocks->len) {
85 /* Delete blocks from a file. Must reclaim memory. */
86 for (guint i = inode->blocks->len; i < blocks; i++) {
87 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, i);
89 bluesky_string_unref(b->data);
91 g_array_set_size(inode->blocks, blocks);
94 /* Ensure the new last block of the file is properly sized. If the block
95 * is extended, newly-added bytes must be zeroed. */
97 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
100 if (b->type != BLUESKY_BLOCK_ZERO) {
101 bluesky_block_touch(inode, blocks - 1);
102 gsize old_size = b->data->len;
103 gsize new_size = size - (blocks - 1) * BLUESKY_BLOCK_SIZE;
105 bluesky_string_resize(b->data, new_size);
107 if (new_size > old_size) {
108 memset(&b->data->data[old_size], 0, new_size - old_size);
114 bluesky_inode_update_ctime(inode, 1);
117 void bluesky_file_write(BlueSkyInode *inode, uint64_t offset,
118 const char *data, gint len)
120 g_print("Write %d bytes at offset %"PRIi64"\n", len, offset);
122 g_return_if_fail(inode->type == BLUESKY_REGULAR);
123 g_return_if_fail(offset < inode->size);
124 g_return_if_fail(len <= inode->size - offset);
130 uint64_t block_num = offset / BLUESKY_BLOCK_SIZE;
131 gint block_offset = offset % BLUESKY_BLOCK_SIZE;
132 gint bytes = MIN(BLUESKY_BLOCK_SIZE - block_offset, len);
134 bluesky_block_touch(inode, block_num);
135 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
137 memcpy(&b->data->data[block_offset], data, bytes);
144 bluesky_inode_update_ctime(inode, 1);
147 void bluesky_file_read(BlueSkyInode *inode, uint64_t offset,
150 g_print("Read %d bytes at offset %"PRIi64"\n", len, offset);
152 if (len == 0 && offset <= inode->size)
155 g_return_if_fail(inode->type == BLUESKY_REGULAR);
156 g_return_if_fail(offset < inode->size);
157 g_return_if_fail(len <= inode->size - offset);
160 uint64_t block_num = offset / BLUESKY_BLOCK_SIZE;
161 gint block_offset = offset % BLUESKY_BLOCK_SIZE;
162 gint bytes = MIN(BLUESKY_BLOCK_SIZE - block_offset, len);
164 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock,
167 case BLUESKY_BLOCK_ZERO:
168 memset(buf, 0, bytes);
170 case BLUESKY_BLOCK_REF:
171 bluesky_block_fetch(inode->fs, b);
173 case BLUESKY_BLOCK_CACHED:
174 case BLUESKY_BLOCK_DIRTY:
175 memcpy(buf, &b->data->data[block_offset], bytes);
185 /* Read the given block from cloud-backed storage if the data is not already
187 void bluesky_block_fetch(BlueSkyFS *fs, BlueSkyBlock *block)
189 if (block->type != BLUESKY_BLOCK_REF)
192 BlueSkyRCStr *string = bluesky_store_get(fs->store, block->ref);
194 bluesky_string_unref(block->data);
195 block->data = string;
196 block->type = BLUESKY_BLOCK_CACHED;
199 /* Write the given block to cloud-backed storage and mark it clean. */
200 void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block,
201 BlueSkyStoreAsync *barrier)
203 if (block->type != BLUESKY_BLOCK_DIRTY)
206 BlueSkyRCStr *data = block->data;
208 GChecksum *csum = g_checksum_new(G_CHECKSUM_SHA256);
209 g_checksum_update(csum, data->data, data->len);
210 gchar *name = g_strdup(g_checksum_get_string(csum));
212 /* Store the file data asynchronously, and don't bother waiting for a
214 BlueSkyStoreAsync *async = bluesky_store_async_new(fs->store);
215 async->op = STORE_OP_PUT;
216 async->key = g_strdup(name);
217 bluesky_string_ref(data);
219 bluesky_store_async_submit(async);
221 bluesky_store_add_barrier(barrier, async);
222 bluesky_store_async_unref(async);
227 /* block->type = BLUESKY_BLOCK_CACHED; */
228 bluesky_string_unref(block->data);
230 block->type = BLUESKY_BLOCK_REF;
232 g_checksum_free(csum);
233 //bluesky_string_unref(data);
236 /* Flush all blocks in a file to stable storage. */
237 void bluesky_file_flush(BlueSkyInode *inode, BlueSkyStoreAsync *barrier)
239 g_return_if_fail(inode->type == BLUESKY_REGULAR);
241 for (int i = 0; i < inode->blocks->len; i++) {
242 BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, i);
243 bluesky_block_flush(inode->fs, b, barrier);