Clarified and cleaned up Coffee's documentation and the debug statements. Formatted some source code for easier reading.

This commit is contained in:
Nicolas Tsiftes 2016-04-20 14:30:20 +02:00
parent 7586195b79
commit 86733e8702
2 changed files with 56 additions and 62 deletions

View file

@ -114,8 +114,7 @@
#define GC_RELUCTANT 1 #define GC_RELUCTANT 1
/* File descriptor macros. */ /* File descriptor macros. */
#define FD_VALID(fd) \ #define FD_VALID(fd) ((fd) >= 0 && (fd) < COFFEE_FD_SET_SIZE && \
((fd) >= 0 && (fd) < COFFEE_FD_SET_SIZE && \
coffee_fd_set[(fd)].flags != COFFEE_FD_FREE) coffee_fd_set[(fd)].flags != COFFEE_FD_FREE)
#define FD_READABLE(fd) (coffee_fd_set[(fd)].flags & CFS_READ) #define FD_READABLE(fd) (coffee_fd_set[(fd)].flags & CFS_READ)
#define FD_WRITABLE(fd) (coffee_fd_set[(fd)].flags & CFS_WRITE) #define FD_WRITABLE(fd) (coffee_fd_set[(fd)].flags & CFS_WRITE)
@ -127,10 +126,10 @@
#define FILE_UNREFERENCED(file) ((file)->references == 0) #define FILE_UNREFERENCED(file) ((file)->references == 0)
/* File header flags. */ /* File header flags. */
#define HDR_FLAG_VALID 0x1 /* Completely written header. */ #define HDR_FLAG_VALID 0x01 /* Completely written header. */
#define HDR_FLAG_ALLOCATED 0x2 /* Allocated file. */ #define HDR_FLAG_ALLOCATED 0x02 /* Allocated file. */
#define HDR_FLAG_OBSOLETE 0x4 /* File marked for GC. */ #define HDR_FLAG_OBSOLETE 0x04 /* File marked for GC. */
#define HDR_FLAG_MODIFIED 0x8 /* Modified file, log exists. */ #define HDR_FLAG_MODIFIED 0x08 /* Modified file, log exists. */
#define HDR_FLAG_LOG 0x10 /* Log file. */ #define HDR_FLAG_LOG 0x10 /* Log file. */
#define HDR_FLAG_ISOLATED 0x20 /* Isolated page. */ #define HDR_FLAG_ISOLATED 0x20 /* Isolated page. */
@ -148,7 +147,8 @@
!HDR_ISOLATED(hdr)) !HDR_ISOLATED(hdr))
/* Shortcuts derived from the hardware-dependent configuration of Coffee. */ /* Shortcuts derived from the hardware-dependent configuration of Coffee. */
#define COFFEE_SECTOR_COUNT (unsigned)(COFFEE_SIZE / COFFEE_SECTOR_SIZE) #define COFFEE_SECTOR_COUNT \
(coffee_page_t)(COFFEE_SIZE / COFFEE_SECTOR_SIZE)
#define COFFEE_PAGE_COUNT \ #define COFFEE_PAGE_COUNT \
((coffee_page_t)(COFFEE_SIZE / COFFEE_PAGE_SIZE)) ((coffee_page_t)(COFFEE_SIZE / COFFEE_PAGE_SIZE))
#define COFFEE_PAGES_PER_SECTOR \ #define COFFEE_PAGES_PER_SECTOR \
@ -235,7 +235,7 @@ absolute_offset(coffee_page_t page, cfs_offset_t offset)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static coffee_page_t static coffee_page_t
get_sector_status(uint16_t sector, struct sector_status *stats) get_sector_status(coffee_page_t sector, struct sector_status *stats)
{ {
static coffee_page_t skip_pages; static coffee_page_t skip_pages;
static char last_pages_are_active; static char last_pages_are_active;
@ -305,7 +305,7 @@ get_sector_status(uint16_t sector, struct sector_status *stats)
/* /*
* Determine the amount of pages in the following sectors that * Determine the amount of pages in the following sectors that
* should be remembered for the next iteration. This is necessary * should be remembered for the next iteration. This is necessary
* because no page except the first of a file contains information * because no file page except the first contains information
* about what type of page it is. A side effect of remembering this * about what type of page it is. A side effect of remembering this
* amount is that there is no need to read in the headers of each * amount is that there is no need to read in the headers of each
* of these pages from the storage. * of these pages from the storage.
@ -356,11 +356,11 @@ isolate_pages(coffee_page_t start, coffee_page_t skip_pages)
static void static void
collect_garbage(int mode) collect_garbage(int mode)
{ {
uint16_t sector; coffee_page_t sector;
struct sector_status stats; struct sector_status stats;
coffee_page_t first_page, isolation_count; coffee_page_t first_page, isolation_count;
PRINTF("Coffee: Running the file system garbage collector in %s mode\n", PRINTF("Coffee: Running the garbage collector in %s mode\n",
mode == GC_RELUCTANT ? "reluctant" : "greedy"); mode == GC_RELUCTANT ? "reluctant" : "greedy");
/* /*
* The garbage collector erases as many sectors as possible. A sector is * The garbage collector erases as many sectors as possible. A sector is
@ -369,7 +369,7 @@ collect_garbage(int mode)
for(sector = 0; sector < COFFEE_SECTOR_COUNT; sector++) { for(sector = 0; sector < COFFEE_SECTOR_COUNT; sector++) {
isolation_count = get_sector_status(sector, &stats); isolation_count = get_sector_status(sector, &stats);
PRINTF("Coffee: Sector %u has %u active, %u obsolete, and %u free pages.\n", PRINTF("Coffee: Sector %u has %u active, %u obsolete, and %u free pages.\n",
sector, (unsigned)stats.active, (unsigned)sector, (unsigned)stats.active,
(unsigned)stats.obsolete, (unsigned)stats.free); (unsigned)stats.obsolete, (unsigned)stats.free);
if(stats.active > 0) { if(stats.active > 0) {
@ -402,7 +402,7 @@ next_file(coffee_page_t page, struct file_header *hdr)
{ {
/* /*
* The quick-skip algorithm for finding file extents is the most * The quick-skip algorithm for finding file extents is the most
* essential part of Coffee. The file allocation rules enables this * essential part of Coffee. The file allocation rules enable this
* algorithm to quickly jump over free areas and allocated extents * algorithm to quickly jump over free areas and allocated extents
* after reading single headers and determining their status. * after reading single headers and determining their status.
* *
@ -648,7 +648,7 @@ reserve(const char *name, coffee_page_t pages,
write_header(&hdr, page); write_header(&hdr, page);
PRINTF("Coffee: Reserved %u pages starting from %u for file %s\n", PRINTF("Coffee: Reserved %u pages starting from %u for file %s\n",
pages, page, name); (unsigned)pages, (unsigned)page, name);
file = load_file(page, &hdr); file = load_file(page, &hdr);
if(file != NULL) { if(file != NULL) {
@ -843,7 +843,7 @@ merge_log(coffee_page_t file_page, int extend)
return -1; return -1;
} }
/* Copy the log configuration and the EOF hint. */ /* Copy the log configuration. */
read_header(&hdr2, new_file->page); read_header(&hdr2, new_file->page);
hdr2.log_record_size = hdr.log_record_size; hdr2.log_record_size = hdr.log_record_size;
hdr2.log_records = hdr.log_records; hdr2.log_records = hdr.log_records;
@ -1102,7 +1102,7 @@ cfs_read(int fd, void *buf, unsigned size)
size = file->end - fdp->offset; size = file->end - fdp->offset;
} }
/* If the file is allocated, read directly in the file. */ /* If the file is not modified, read directly from the file extent. */
if(!FILE_MODIFIED(file)) { if(!FILE_MODIFIED(file)) {
COFFEE_READ(buf, size, absolute_offset(file->page, fdp->offset)); COFFEE_READ(buf, size, absolute_offset(file->page, fdp->offset));
fdp->offset += size; fdp->offset += size;
@ -1113,8 +1113,9 @@ cfs_read(int fd, void *buf, unsigned size)
read_header(&hdr, file->page); read_header(&hdr, file->page);
/* /*
* Fill the buffer by copying from the log in first hand, or the * Copy the contents of the most recent log record. If there is
* ordinary file if the page has no log record. * no log record for the file area to read from, we simply read
* from the original file extent.
*/ */
for(bytes_left = size; bytes_left > 0; bytes_left -= r) { for(bytes_left = size; bytes_left > 0; bytes_left -= r) {
lp.offset = fdp->offset; lp.offset = fdp->offset;
@ -1242,8 +1243,8 @@ int
cfs_opendir(struct cfs_dir *dir, const char *name) cfs_opendir(struct cfs_dir *dir, const char *name)
{ {
/* /*
* Coffee is only guaranteed to support "/" and ".", but it does not * Coffee is only guaranteed to support the directory names "/" and ".",
* currently enforce this. * but it does not enforce this currently.
*/ */
memset(dir->dummy_space, 0, sizeof(coffee_page_t)); memset(dir->dummy_space, 0, sizeof(coffee_page_t));
return 0; return 0;
@ -1254,13 +1255,13 @@ cfs_readdir(struct cfs_dir *dir, struct cfs_dirent *record)
{ {
struct file_header hdr; struct file_header hdr;
coffee_page_t page; coffee_page_t page;
coffee_page_t next_page;
memcpy(&page, dir->dummy_space, sizeof(coffee_page_t)); memcpy(&page, dir->dummy_space, sizeof(coffee_page_t));
while(page < COFFEE_PAGE_COUNT) { while(page < COFFEE_PAGE_COUNT) {
read_header(&hdr, page); read_header(&hdr, page);
if(HDR_ACTIVE(hdr) && !HDR_LOG(hdr)) { if(HDR_ACTIVE(hdr) && !HDR_LOG(hdr)) {
coffee_page_t next_page;
memcpy(record->name, hdr.name, sizeof(record->name)); memcpy(record->name, hdr.name, sizeof(record->name));
record->name[sizeof(record->name) - 1] = '\0'; record->name[sizeof(record->name) - 1] = '\0';
record->size = file_end(page); record->size = file_end(page);
@ -1334,9 +1335,9 @@ cfs_coffee_set_io_semantics(int fd, unsigned flags)
int int
cfs_coffee_format(void) cfs_coffee_format(void)
{ {
unsigned i; coffee_page_t i;
PRINTF("Coffee: Formatting %u sectors", COFFEE_SECTOR_COUNT); PRINTF("Coffee: Formatting %u sectors", (unsigned)COFFEE_SECTOR_COUNT);
for(i = 0; i < COFFEE_SECTOR_COUNT; i++) { for(i = 0; i < COFFEE_SECTOR_COUNT; i++) {
COFFEE_ERASE(i); COFFEE_ERASE(i);

View file

@ -46,15 +46,15 @@
* invoke its own micro logs when file modifications occur. * invoke its own micro logs when file modifications occur.
* *
* This semantical I/O setting is useful when implementing flash storage * This semantical I/O setting is useful when implementing flash storage
* algorithms on top of Coffee. * algorithms such as database indices on top of Coffee.
* *
* \sa cfs_coffee_set_io_semantics() * \sa cfs_coffee_set_io_semantics()
*/ */
#define CFS_COFFEE_IO_FLASH_AWARE 0x1 #define CFS_COFFEE_IO_FLASH_AWARE 0x1
/** /**
* Instruct Coffee not to attempt to extend the file when there is * Instruct Coffee not to attempt to extend the file upon a request
* an attempt to write past the reserved file size. * to write past the reserved file size.
* *
* A case when this is necessary is when the file has a firm size limit, * A case when this is necessary is when the file has a firm size limit,
* and a safeguard is needed to protect against writes beyond this limit. * and a safeguard is needed to protect against writes beyond this limit.
@ -75,8 +75,8 @@
/** /**
* \brief Reserve space for a file. * \brief Reserve space for a file.
* \param name The filename. * \param name The file name.
* \param size The size of the file. * \param size The initial size to be reserved for the file.
* \return 0 on success, -1 on failure. * \return 0 on success, -1 on failure.
* *
* Coffee uses sequential page structures for files. The sequential * Coffee uses sequential page structures for files. The sequential
@ -88,15 +88,15 @@ int cfs_coffee_reserve(const char *name, cfs_offset_t size);
/** /**
* \brief Configure the on-demand log file. * \brief Configure the on-demand log file.
* \param file The filename. * \param file The file name.
* \param log_size The total log size. * \param log_size The total log file size.
* \param log_entry_size The log entry size. * \param log_entry_size The log entry size.
* \return 0 on success, -1 on failure. * \return 0 on success, -1 on failure.
* *
* When file data is first modified, Coffee creates a micro log for the * When file data is first modified, Coffee creates a micro log for the
* file. The micro log stores a table of modifications whose * file. The micro log stores a table of modifications whose parameters --
* parameters--the log size and the log entry size--can be modified * the log size and the log entry size -- can be modified through the
* through the cfs_coffee_configure_log function. * cfs_coffee_configure_log function.
*/ */
int cfs_coffee_configure_log(const char *file, unsigned log_size, int cfs_coffee_configure_log(const char *file, unsigned log_size,
unsigned log_entry_size); unsigned log_entry_size);
@ -109,8 +109,8 @@ int cfs_coffee_configure_log(const char *file, unsigned log_size,
* *
* Coffee is used on a wide range of storage types, and the default * Coffee is used on a wide range of storage types, and the default
* I/O file semantics may not be optimal for the access pattern * I/O file semantics may not be optimal for the access pattern
* of a certain file. Hence, this functions allows programmers to * of a certain file. Hence, this function allows programmers to
* switch the /O semantics on a file that is accessed through a * switch the I/O semantics on a file that is accessed through a
* particular file descriptor. * particular file descriptor.
* *
*/ */
@ -123,21 +123,14 @@ int cfs_coffee_set_io_semantics(int fd, unsigned flags);
* Coffee formats the underlying storage by setting all bits to zero. * Coffee formats the underlying storage by setting all bits to zero.
* Formatting must be done before using Coffee for the first time in * Formatting must be done before using Coffee for the first time in
* a mote. * a mote.
*
* Notice that the erased bits may be set to 1 on the physical storage
* when using flash memory. In this case, Coffee requires that the
* COFFEE_READ and COFFEE_WRITE functions used to access the flash memory
* invert all bits.
*/ */
int cfs_coffee_format(void); int cfs_coffee_format(void);
/**
* \brief Points out a memory region that may not be altered during
* checkpointing operations that use the file system.
* \param size
* \return A pointer to the protected memory.
*
* This function returns the protected memory pointer and writes its size
* to the given parameter. Mainly used by sensornet checkpointing to protect
* the coffee state during CFS-based checkpointing operations.
*/
void *cfs_coffee_get_protected_mem(unsigned *size);
/** @} */ /** @} */
/** @} */ /** @} */