Corrected some code style issues in Coffee.

This commit is contained in:
Nicolas Tsiftes 2015-02-17 11:02:06 +01:00
parent 6e3119234b
commit da04ec74ed

View file

@ -35,12 +35,12 @@
* Coffee: A file system for a variety of storage types in * Coffee: A file system for a variety of storage types in
* memory-constrained devices. * memory-constrained devices.
* *
* For further information, see "Enabling Large-Scale Storage in * For further information, see "Enabling Large-Scale Storage in
* Sensor Networks with the Coffee File System" in the proceedings * Sensor Networks with the Coffee File System" in the proceedings
* of ACM/IEEE IPSN 2009. * of ACM/IEEE IPSN 2009.
* *
* \author * \author
* Nicolas Tsiftes <nvt@sics.se> * Nicolas Tsiftes <nvt@sics.se>
*/ */
#include <limits.h> #include <limits.h>
@ -62,23 +62,23 @@
/* Micro logs enable modifications on storage types that do not support /* Micro logs enable modifications on storage types that do not support
in-place updates. This applies primarily to flash memories. */ in-place updates. This applies primarily to flash memories. */
#ifndef COFFEE_MICRO_LOGS #ifndef COFFEE_MICRO_LOGS
#define COFFEE_MICRO_LOGS 1 #define COFFEE_MICRO_LOGS 1
#endif #endif
/* If the files are expected to be appended to only, this parameter /* If the files are expected to be appended to only, this parameter
can be set to save some code space. */ can be set to save some code space. */
#ifndef COFFEE_APPEND_ONLY #ifndef COFFEE_APPEND_ONLY
#define COFFEE_APPEND_ONLY 0 #define COFFEE_APPEND_ONLY 0
#endif #endif
#if COFFEE_MICRO_LOGS && COFFEE_APPEND_ONLY #if COFFEE_MICRO_LOGS && COFFEE_APPEND_ONLY
#error "Cannot have COFFEE_APPEND_ONLY set when COFFEE_MICRO_LOGS is set." #error "Cannot have COFFEE_APPEND_ONLY set when COFFEE_MICRO_LOGS is set."
#endif #endif
/* I/O semantics can be set on file descriptors in order to optimize /* I/O semantics can be set on file descriptors in order to optimize
file access on certain storage types. */ file access on certain storage types. */
#ifndef COFFEE_IO_SEMANTICS #ifndef COFFEE_IO_SEMANTICS
#define COFFEE_IO_SEMANTICS 0 #define COFFEE_IO_SEMANTICS 0
#endif #endif
/* /*
@ -87,72 +87,72 @@
* to longer garbage collection procedures. * to longer garbage collection procedures.
*/ */
#ifndef COFFEE_EXTENDED_WEAR_LEVELLING #ifndef COFFEE_EXTENDED_WEAR_LEVELLING
#define COFFEE_EXTENDED_WEAR_LEVELLING 1 #define COFFEE_EXTENDED_WEAR_LEVELLING 1
#endif #endif
#if COFFEE_START & (COFFEE_SECTOR_SIZE - 1) #if COFFEE_START & (COFFEE_SECTOR_SIZE - 1)
#error COFFEE_START must point to the first byte in a sector. #error COFFEE_START must point to the first byte in a sector.
#endif #endif
#define COFFEE_FD_FREE 0x0 #define COFFEE_FD_FREE 0x0
#define COFFEE_FD_READ 0x1 #define COFFEE_FD_READ 0x1
#define COFFEE_FD_WRITE 0x2 #define COFFEE_FD_WRITE 0x2
#define COFFEE_FD_APPEND 0x4 #define COFFEE_FD_APPEND 0x4
#define COFFEE_FILE_MODIFIED 0x1 #define COFFEE_FILE_MODIFIED 0x1
#define INVALID_PAGE ((coffee_page_t)-1) #define INVALID_PAGE ((coffee_page_t)-1)
#define UNKNOWN_OFFSET ((cfs_offset_t)-1) #define UNKNOWN_OFFSET ((cfs_offset_t)-1)
#define REMOVE_LOG 1 #define REMOVE_LOG 1
#define CLOSE_FDS 1 #define CLOSE_FDS 1
#define ALLOW_GC 1 #define ALLOW_GC 1
/* "Greedy" garbage collection erases as many sectors as possible. */ /* "Greedy" garbage collection erases as many sectors as possible. */
#define GC_GREEDY 0 #define GC_GREEDY 0
/* "Reluctant" garbage collection stops after erasing one sector. */ /* "Reluctant" garbage collection stops after erasing one sector. */
#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)
#define FD_APPENDABLE(fd) (coffee_fd_set[(fd)].flags & CFS_APPEND) #define FD_APPENDABLE(fd) (coffee_fd_set[(fd)].flags & CFS_APPEND)
/* File object macros. */ /* File object macros. */
#define FILE_MODIFIED(file) ((file)->flags & COFFEE_FILE_MODIFIED) #define FILE_MODIFIED(file) ((file)->flags & COFFEE_FILE_MODIFIED)
#define FILE_FREE(file) ((file)->max_pages == 0) #define FILE_FREE(file) ((file)->max_pages == 0)
#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 0x1 /* Completely written header. */
#define HDR_FLAG_ALLOCATED 0x2 /* Allocated file. */ #define HDR_FLAG_ALLOCATED 0x2 /* Allocated file. */
#define HDR_FLAG_OBSOLETE 0x4 /* File marked for GC. */ #define HDR_FLAG_OBSOLETE 0x4 /* File marked for GC. */
#define HDR_FLAG_MODIFIED 0x8 /* Modified file, log exists. */ #define HDR_FLAG_MODIFIED 0x8 /* 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. */
/* File header macros. */ /* File header macros. */
#define CHECK_FLAG(hdr, flag) ((hdr).flags & (flag)) #define CHECK_FLAG(hdr, flag) ((hdr).flags & (flag))
#define HDR_VALID(hdr) CHECK_FLAG(hdr, HDR_FLAG_VALID) #define HDR_VALID(hdr) CHECK_FLAG(hdr, HDR_FLAG_VALID)
#define HDR_ALLOCATED(hdr) CHECK_FLAG(hdr, HDR_FLAG_ALLOCATED) #define HDR_ALLOCATED(hdr) CHECK_FLAG(hdr, HDR_FLAG_ALLOCATED)
#define HDR_FREE(hdr) !HDR_ALLOCATED(hdr) #define HDR_FREE(hdr) !HDR_ALLOCATED(hdr)
#define HDR_LOG(hdr) CHECK_FLAG(hdr, HDR_FLAG_LOG) #define HDR_LOG(hdr) CHECK_FLAG(hdr, HDR_FLAG_LOG)
#define HDR_MODIFIED(hdr) CHECK_FLAG(hdr, HDR_FLAG_MODIFIED) #define HDR_MODIFIED(hdr) CHECK_FLAG(hdr, HDR_FLAG_MODIFIED)
#define HDR_ISOLATED(hdr) CHECK_FLAG(hdr, HDR_FLAG_ISOLATED) #define HDR_ISOLATED(hdr) CHECK_FLAG(hdr, HDR_FLAG_ISOLATED)
#define HDR_OBSOLETE(hdr) CHECK_FLAG(hdr, HDR_FLAG_OBSOLETE) #define HDR_OBSOLETE(hdr) CHECK_FLAG(hdr, HDR_FLAG_OBSOLETE)
#define HDR_ACTIVE(hdr) (HDR_ALLOCATED(hdr) && \ #define HDR_ACTIVE(hdr) (HDR_ALLOCATED(hdr) && \
!HDR_OBSOLETE(hdr) && \ !HDR_OBSOLETE(hdr) && \
!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 (unsigned)(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 \
((coffee_page_t)(COFFEE_SECTOR_SIZE / COFFEE_PAGE_SIZE)) ((coffee_page_t)(COFFEE_SECTOR_SIZE / COFFEE_PAGE_SIZE))
/* This structure is used for garbage collection statistics. */ /* This structure is used for garbage collection statistics. */
struct sector_status { struct sector_status {
@ -181,7 +181,7 @@ struct file_desc {
#endif #endif
}; };
/* The file header structure mimics the representation of file headers /* The file header structure mimics the representation of file headers
in the physical storage medium. */ in the physical storage medium. */
struct file_header { struct file_header {
coffee_page_t log_page; coffee_page_t log_page;
@ -201,9 +201,9 @@ struct log_param {
}; };
/* /*
* The protected memory consists of structures that should not be * The protected memory consists of structures that should not be
* overwritten during system checkpointing because they may be used by * overwritten during system checkpointing because they may be used by
* the checkpointing implementation. These structures need not be * the checkpointing implementation. These structures need not be
* protected if checkpointing is not used. * protected if checkpointing is not used.
*/ */
static struct protected_mem_t { static struct protected_mem_t {
@ -212,10 +212,10 @@ static struct protected_mem_t {
coffee_page_t next_free; coffee_page_t next_free;
char gc_wait; char gc_wait;
} protected_mem; } protected_mem;
static struct file * const coffee_files = protected_mem.coffee_files; static struct file *const coffee_files = protected_mem.coffee_files;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set; static struct file_desc *const coffee_fd_set = protected_mem.coffee_fd_set;
static coffee_page_t * const next_free = &protected_mem.next_free; static coffee_page_t *const next_free = &protected_mem.next_free;
static char * const gc_wait = &protected_mem.gc_wait; static char *const gc_wait = &protected_mem.gc_wait;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
@ -256,8 +256,8 @@ get_sector_status(uint16_t sector, struct sector_status *stats)
active = obsolete = free = 0; active = obsolete = free = 0;
/* /*
* get_sector_status() is an iterative function using local static * get_sector_status() is an iterative function using local static
* state. It therefore requires that the caller starts iterating from * state. It therefore requires that the caller starts iterating from
* sector 0 in order to reset the internal state. * sector 0 in order to reset the internal state.
*/ */
if(sector == 0) { if(sector == 0) {
@ -269,8 +269,8 @@ get_sector_status(uint16_t sector, struct sector_status *stats)
sector_end = sector_start + COFFEE_PAGES_PER_SECTOR; sector_end = sector_start + COFFEE_PAGES_PER_SECTOR;
/* /*
* Account for pages belonging to a file starting in a previous * Account for pages belonging to a file starting in a previous
* segment that extends into this segment. If the whole segment is * segment that extends into this segment. If the whole segment is
* covered, we do not need to continue counting pages in this iteration. * covered, we do not need to continue counting pages in this iteration.
*/ */
if(last_pages_are_active) { if(last_pages_are_active) {
@ -289,7 +289,7 @@ get_sector_status(uint16_t sector, struct sector_status *stats)
obsolete = skip_pages; obsolete = skip_pages;
} }
/* Determine the amount of pages of each type that have not been /* Determine the amount of pages of each type that have not been
accounted for yet in the current sector. */ accounted for yet in the current sector. */
for(page = sector_start + skip_pages; page < sector_end;) { for(page = sector_start + skip_pages; page < sector_end;) {
read_header(&hdr, page); read_header(&hdr, page);
@ -312,10 +312,10 @@ 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 page except the first of a file 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.
*/ */
skip_pages = active + obsolete + free - COFFEE_PAGES_PER_SECTOR; skip_pages = active + obsolete + free - COFFEE_PAGES_PER_SECTOR;
@ -332,14 +332,14 @@ get_sector_status(uint16_t sector, struct sector_status *stats)
stats->free = free; stats->free = free;
/* /*
* To avoid unnecessary page isolation, we notify the caller that * To avoid unnecessary page isolation, we notify the caller that
* "skip_pages" pages should be isolated only if the current file extent * "skip_pages" pages should be isolated only if the current file extent
* ends in the next sector. If the file extent ends in a more distant * ends in the next sector. If the file extent ends in a more distant
* sector, however, the garbage collection can free the next sector * sector, however, the garbage collection can free the next sector
* immediately without requiring page isolation. * immediately without requiring page isolation.
*/ */
return (last_pages_are_active || (skip_pages >= COFFEE_PAGES_PER_SECTOR)) ? return (last_pages_are_active || (skip_pages >= COFFEE_PAGES_PER_SECTOR)) ?
0 : skip_pages; 0 : skip_pages;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
@ -359,7 +359,6 @@ isolate_pages(coffee_page_t start, coffee_page_t skip_pages)
} }
PRINTF("Coffee: Isolated %u pages starting in sector %d\n", PRINTF("Coffee: Isolated %u pages starting in sector %d\n",
(unsigned)skip_pages, (int)start / COFFEE_PAGES_PER_SECTOR); (unsigned)skip_pages, (int)start / COFFEE_PAGES_PER_SECTOR);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
@ -370,7 +369,7 @@ collect_garbage(int mode)
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 file system 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
* erasable if there are only free or obsolete pages in it. * erasable if there are only free or obsolete pages in it.
@ -378,8 +377,8 @@ 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, sector, (unsigned)stats.active,
(unsigned)stats.obsolete, (unsigned)stats.free); (unsigned)stats.obsolete, (unsigned)stats.free);
if(stats.active > 0) { if(stats.active > 0) {
continue; continue;
@ -410,13 +409,13 @@ static coffee_page_t
next_file(coffee_page_t page, struct file_header *hdr) 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 enables 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.
* *
* The worst-case performance occurs when we encounter multiple long * The worst-case performance occurs when we encounter multiple long
* sequences of isolated pages, but such sequences are uncommon and * sequences of isolated pages, but such sequences are uncommon and
* always shorter than a sector. * always shorter than a sector.
*/ */
if(HDR_FREE(*hdr)) { if(HDR_FREE(*hdr)) {
@ -424,7 +423,7 @@ next_file(coffee_page_t page, struct file_header *hdr)
} else if(HDR_ISOLATED(*hdr)) { } else if(HDR_ISOLATED(*hdr)) {
return page + 1; return page + 1;
} }
return page + hdr->max_pages; return page + hdr->max_pages;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static struct file * static struct file *
@ -475,7 +474,7 @@ find_file(const char *name)
int i; int i;
struct file_header hdr; struct file_header hdr;
coffee_page_t page; coffee_page_t page;
/* First check if the file metadata is cached. */ /* First check if the file metadata is cached. */
for(i = 0; i < COFFEE_MAX_OPEN_FILES; i++) { for(i = 0; i < COFFEE_MAX_OPEN_FILES; i++) {
if(FILE_FREE(&coffee_files[i])) { if(FILE_FREE(&coffee_files[i])) {
@ -487,7 +486,7 @@ find_file(const char *name)
return &coffee_files[i]; return &coffee_files[i];
} }
} }
/* Scan the flash memory sequentially otherwise. */ /* Scan the flash memory sequentially otherwise. */
for(page = 0; page < COFFEE_PAGE_COUNT; page = next_file(page, &hdr)) { for(page = 0; page < COFFEE_PAGE_COUNT; page = next_file(page, &hdr)) {
read_header(&hdr, page); read_header(&hdr, page);
@ -521,10 +520,10 @@ file_end(coffee_page_t start)
COFFEE_READ(buf, sizeof(buf), (start + page) * COFFEE_PAGE_SIZE); COFFEE_READ(buf, sizeof(buf), (start + page) * COFFEE_PAGE_SIZE);
for(i = COFFEE_PAGE_SIZE - 1; i >= 0; i--) { for(i = COFFEE_PAGE_SIZE - 1; i >= 0; i--) {
if(buf[i] != 0) { if(buf[i] != 0) {
if(page == 0 && i < sizeof(hdr)) { if(page == 0 && i < sizeof(hdr)) {
return 0; return 0;
} }
return 1 + i + (page * COFFEE_PAGE_SIZE) - sizeof(hdr); return 1 + i + (page * COFFEE_PAGE_SIZE) - sizeof(hdr);
} }
} }
} }
@ -544,7 +543,7 @@ find_contiguous_pages(coffee_page_t amount)
read_header(&hdr, page); read_header(&hdr, page);
if(HDR_FREE(hdr)) { if(HDR_FREE(hdr)) {
if(start == INVALID_PAGE) { if(start == INVALID_PAGE) {
start = page; start = page;
if(start + amount >= COFFEE_PAGE_COUNT) { if(start + amount >= COFFEE_PAGE_COUNT) {
/* We can stop immediately if the remaining pages are not enough. */ /* We can stop immediately if the remaining pages are not enough. */
break; break;
@ -557,9 +556,9 @@ find_contiguous_pages(coffee_page_t amount)
if(start + amount <= page) { if(start + amount <= page) {
if(start == *next_free) { if(start == *next_free) {
*next_free = start + amount; *next_free = start + amount;
} }
return start; return start;
} }
} else { } else {
start = INVALID_PAGE; start = INVALID_PAGE;
@ -596,7 +595,7 @@ remove_by_page(coffee_page_t page, int remove_log, int close_fds,
if(close_fds) { if(close_fds) {
for(i = 0; i < COFFEE_FD_SET_SIZE; i++) { for(i = 0; i < COFFEE_FD_SET_SIZE; i++) {
if(coffee_fd_set[i].file != NULL && coffee_fd_set[i].file->page == page) { if(coffee_fd_set[i].file != NULL && coffee_fd_set[i].file->page == page) {
coffee_fd_set[i].flags = COFFEE_FD_FREE; coffee_fd_set[i].flags = COFFEE_FD_FREE;
} }
} }
} }
@ -622,12 +621,12 @@ static coffee_page_t
page_count(cfs_offset_t size) page_count(cfs_offset_t size)
{ {
return (size + sizeof(struct file_header) + COFFEE_PAGE_SIZE - 1) / return (size + sizeof(struct file_header) + COFFEE_PAGE_SIZE - 1) /
COFFEE_PAGE_SIZE; COFFEE_PAGE_SIZE;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static struct file * static struct file *
reserve(const char *name, coffee_page_t pages, reserve(const char *name, coffee_page_t pages,
int allow_duplicates, unsigned flags) int allow_duplicates, unsigned flags)
{ {
struct file_header hdr; struct file_header hdr;
coffee_page_t page; coffee_page_t page;
@ -657,7 +656,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); pages, page, name);
file = load_file(page, &hdr); file = load_file(page, &hdr);
if(file != NULL) { if(file != NULL) {
@ -670,19 +669,19 @@ reserve(const char *name, coffee_page_t pages,
#if COFFEE_MICRO_LOGS #if COFFEE_MICRO_LOGS
static void static void
adjust_log_config(struct file_header *hdr, adjust_log_config(struct file_header *hdr,
uint16_t *log_record_size, uint16_t *log_records) uint16_t *log_record_size, uint16_t *log_records)
{ {
*log_record_size = hdr->log_record_size == 0 ? *log_record_size = hdr->log_record_size == 0 ?
COFFEE_PAGE_SIZE : hdr->log_record_size; COFFEE_PAGE_SIZE : hdr->log_record_size;
*log_records = hdr->log_records == 0 ? *log_records = hdr->log_records == 0 ?
COFFEE_LOG_SIZE / *log_record_size : hdr->log_records; COFFEE_LOG_SIZE / *log_record_size : hdr->log_records;
} }
#endif /* COFFEE_MICRO_LOGS */ #endif /* COFFEE_MICRO_LOGS */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#if COFFEE_MICRO_LOGS #if COFFEE_MICRO_LOGS
static uint16_t static uint16_t
modify_log_buffer(uint16_t log_record_size, modify_log_buffer(uint16_t log_record_size,
cfs_offset_t *offset, uint16_t *size) cfs_offset_t *offset, uint16_t *size)
{ {
uint16_t region; uint16_t region;
@ -700,7 +699,7 @@ modify_log_buffer(uint16_t log_record_size,
#if COFFEE_MICRO_LOGS #if COFFEE_MICRO_LOGS
static int static int
get_record_index(coffee_page_t log_page, uint16_t search_records, get_record_index(coffee_page_t log_page, uint16_t search_records,
uint16_t region) uint16_t region)
{ {
cfs_offset_t base; cfs_offset_t base;
uint16_t processed; uint16_t processed;
@ -709,30 +708,30 @@ get_record_index(coffee_page_t log_page, uint16_t search_records,
base = absolute_offset(log_page, sizeof(uint16_t) * search_records); base = absolute_offset(log_page, sizeof(uint16_t) * search_records);
batch_size = search_records > COFFEE_LOG_TABLE_LIMIT ? batch_size = search_records > COFFEE_LOG_TABLE_LIMIT ?
COFFEE_LOG_TABLE_LIMIT : search_records; COFFEE_LOG_TABLE_LIMIT : search_records;
processed = 0; processed = 0;
match_index = -1; match_index = -1;
{ {
uint16_t indices[batch_size]; uint16_t indices[batch_size];
while(processed < search_records && match_index < 0) { while(processed < search_records && match_index < 0) {
if(batch_size + processed > search_records) { if(batch_size + processed > search_records) {
batch_size = search_records - processed; batch_size = search_records - processed;
}
base -= batch_size * sizeof(indices[0]);
COFFEE_READ(&indices, sizeof(indices[0]) * batch_size, base);
for(i = batch_size - 1; i >= 0; i--) {
if(indices[i] - 1 == region) {
match_index = search_records - processed - (batch_size - i);
break;
} }
}
processed += batch_size; base -= batch_size * sizeof(indices[0]);
} COFFEE_READ(&indices, sizeof(indices[0]) * batch_size, base);
for(i = batch_size - 1; i >= 0; i--) {
if(indices[i] - 1 == region) {
match_index = search_records - processed - (batch_size - i);
break;
}
}
processed += batch_size;
}
} }
return match_index; return match_index;
@ -839,7 +838,7 @@ merge_log(coffee_page_t file_page, int extend)
} while(n != 0); } while(n != 0);
for(i = 0; i < COFFEE_FD_SET_SIZE; i++) { for(i = 0; i < COFFEE_FD_SET_SIZE; i++) {
if(coffee_fd_set[i].flags != COFFEE_FD_FREE && if(coffee_fd_set[i].flags != COFFEE_FD_FREE &&
coffee_fd_set[i].file->page == file_page) { coffee_fd_set[i].file->page == file_page) {
coffee_fd_set[i].file = new_file; coffee_fd_set[i].file = new_file;
new_file->references++; new_file->references++;
@ -869,7 +868,7 @@ merge_log(coffee_page_t file_page, int extend)
#if COFFEE_MICRO_LOGS #if COFFEE_MICRO_LOGS
static int static int
find_next_record(struct file *file, coffee_page_t log_page, find_next_record(struct file *file, coffee_page_t log_page,
int log_records) int log_records)
{ {
int log_record, preferred_batch_size; int log_record, preferred_batch_size;
@ -878,7 +877,7 @@ find_next_record(struct file *file, coffee_page_t log_page,
} }
preferred_batch_size = log_records > COFFEE_LOG_TABLE_LIMIT ? preferred_batch_size = log_records > COFFEE_LOG_TABLE_LIMIT ?
COFFEE_LOG_TABLE_LIMIT : log_records; COFFEE_LOG_TABLE_LIMIT : log_records;
{ {
/* The next log record is unknown at this point; search for it. */ /* The next log record is unknown at this point; search for it. */
uint16_t indices[preferred_batch_size]; uint16_t indices[preferred_batch_size];
@ -888,15 +887,15 @@ find_next_record(struct file *file, coffee_page_t log_page,
log_record = log_records; log_record = log_records;
for(processed = 0; processed < log_records; processed += batch_size) { for(processed = 0; processed < log_records; processed += batch_size) {
batch_size = log_records - processed >= preferred_batch_size ? batch_size = log_records - processed >= preferred_batch_size ?
preferred_batch_size : log_records - processed; preferred_batch_size : log_records - processed;
COFFEE_READ(&indices, batch_size * sizeof(indices[0]), COFFEE_READ(&indices, batch_size * sizeof(indices[0]),
absolute_offset(log_page, processed * sizeof(indices[0]))); absolute_offset(log_page, processed * sizeof(indices[0])));
for(log_record = 0; log_record < batch_size; log_record++) { for(log_record = 0; log_record < batch_size; log_record++) {
if(indices[log_record] == 0) { if(indices[log_record] == 0) {
log_record += processed; log_record += processed;
break; break;
} }
} }
} }
} }
@ -940,7 +939,7 @@ write_log_page(struct file *file, struct log_param *lp)
return -1; return -1;
} }
PRINTF("Coffee: Created a log structure for file %s at page %u\n", PRINTF("Coffee: Created a log structure for file %s at page %u\n",
hdr.name, (unsigned)log_page); hdr.name, (unsigned)log_page);
hdr.log_page = log_page; hdr.log_page = log_page;
log_record = 0; log_record = 0;
} }
@ -953,9 +952,9 @@ write_log_page(struct file *file, struct log_param *lp)
lp_out.size = log_record_size; lp_out.size = log_record_size;
if((lp->offset > 0 || lp->size != log_record_size) && if((lp->offset > 0 || lp->size != log_record_size) &&
read_log_page(&hdr, log_record, &lp_out) < 0) { read_log_page(&hdr, log_record, &lp_out) < 0) {
COFFEE_READ(copy_buf, sizeof(copy_buf), COFFEE_READ(copy_buf, sizeof(copy_buf),
absolute_offset(file->page, offset)); absolute_offset(file->page, offset));
} }
memcpy(&copy_buf[lp->offset], lp->buf, lp->size); memcpy(&copy_buf[lp->offset], lp->buf, lp->size);
@ -967,11 +966,11 @@ write_log_page(struct file *file, struct log_param *lp)
offset = absolute_offset(log_page, 0); offset = absolute_offset(log_page, 0);
++region; ++region;
COFFEE_WRITE(&region, sizeof(region), COFFEE_WRITE(&region, sizeof(region),
offset + log_record * sizeof(region)); offset + log_record * sizeof(region));
offset += log_records * sizeof(region); offset += log_records * sizeof(region);
COFFEE_WRITE(copy_buf, sizeof(copy_buf), COFFEE_WRITE(copy_buf, sizeof(copy_buf),
offset + log_record * log_record_size); offset + log_record * log_record_size);
file->record_count = log_record + 1; file->record_count = log_record + 1;
} }
@ -1171,7 +1170,7 @@ cfs_write(int fd, const void *buf, unsigned size)
if(!(fdp->io_flags & CFS_COFFEE_IO_FIRM_SIZE)) { if(!(fdp->io_flags & CFS_COFFEE_IO_FIRM_SIZE)) {
#endif #endif
while(size + fdp->offset + sizeof(struct file_header) > while(size + fdp->offset + sizeof(struct file_header) >
(file->max_pages * COFFEE_PAGE_SIZE)) { (file->max_pages * COFFEE_PAGE_SIZE)) {
if(merge_log(file->page, 1) < 0) { if(merge_log(file->page, 1) < 0) {
return -1; return -1;
} }
@ -1179,7 +1178,7 @@ cfs_write(int fd, const void *buf, unsigned size)
PRINTF("Extended the file at page %u\n", (unsigned)file->page); PRINTF("Extended the file at page %u\n", (unsigned)file->page);
} }
#if COFFEE_IO_SEMANTICS #if COFFEE_IO_SEMANTICS
} }
#endif #endif
#if COFFEE_MICRO_LOGS #if COFFEE_MICRO_LOGS
@ -1196,19 +1195,19 @@ cfs_write(int fd, const void *buf, unsigned size)
lp.size = bytes_left; lp.size = bytes_left;
i = write_log_page(file, &lp); i = write_log_page(file, &lp);
if(i < 0) { if(i < 0) {
/* Return -1 if we wrote nothing because the log write failed. */ /* Return -1 if we wrote nothing because the log write failed. */
if(size == bytes_left) { if(size == bytes_left) {
return -1; return -1;
} }
break; break;
} else if(i == 0) { } else if(i == 0) {
/* The file was merged with the log. */ /* The file was merged with the log. */
file = fdp->file; file = fdp->file;
} else { } else {
/* A log record was written. */ /* A log record was written. */
bytes_left -= i; bytes_left -= i;
fdp->offset += i; fdp->offset += i;
buf = (char *)buf + i; buf = (char *)buf + i;
/* Update the file end for a potential log merge that might /* Update the file end for a potential log merge that might
occur while writing log records. */ occur while writing log records. */
@ -1231,15 +1230,15 @@ cfs_write(int fd, const void *buf, unsigned size)
} else { } else {
#endif /* COFFEE_MICRO_LOGS */ #endif /* COFFEE_MICRO_LOGS */
#if COFFEE_APPEND_ONLY #if COFFEE_APPEND_ONLY
if(fdp->offset < file->end) { if(fdp->offset < file->end) {
return -1; return -1;
} }
#endif /* COFFEE_APPEND_ONLY */ #endif /* COFFEE_APPEND_ONLY */
COFFEE_WRITE(buf, size, absolute_offset(file->page, fdp->offset)); COFFEE_WRITE(buf, size, absolute_offset(file->page, fdp->offset));
fdp->offset += size; fdp->offset += size;
#if COFFEE_MICRO_LOGS #if COFFEE_MICRO_LOGS
} }
#endif /* COFFEE_MICRO_LOGS */ #endif /* COFFEE_MICRO_LOGS */
if(fdp->offset > file->end) { if(fdp->offset > file->end) {
@ -1253,7 +1252,7 @@ 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 "/" and ".", but it does not
* currently enforce this. * currently enforce this.
*/ */
memset(dir->dummy_space, 0, sizeof(coffee_page_t)); memset(dir->dummy_space, 0, sizeof(coffee_page_t));
@ -1300,7 +1299,7 @@ cfs_coffee_reserve(const char *name, cfs_offset_t size)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
int int
cfs_coffee_configure_log(const char *filename, unsigned log_size, cfs_coffee_configure_log(const char *filename, unsigned log_size,
unsigned log_record_size) unsigned log_record_size)
{ {
struct file *file; struct file *file;
struct file_header hdr; struct file_header hdr;