43 #include "lib/random.h" 
   45 #define DEBUG DEBUG_NONE 
   51 struct attribute_record {
 
   52   char name[ATTRIBUTE_NAME_LENGTH];
 
   58   char attribute_name[ATTRIBUTE_NAME_LENGTH];
 
   59   char file_name[DB_MAX_FILENAME_LENGTH];
 
   64 #define DB_COFFEE_CATALOG_SIZE RELATION_NAME_LENGTH +                     \ 
   65                                (DB_MAX_ATTRIBUTES_PER_RELATION *          \ 
   66                                sizeof(struct attribute_record)) 
   72 merge_strings(
char *dest, 
char *prefix, 
char *suffix)
 
   79 storage_generate_file(
char *prefix, 
unsigned long size)
 
   81   static char filename[ATTRIBUTE_NAME_LENGTH + 
sizeof(
".ffff")];
 
   82 #if !DB_FEATURE_COFFEE 
   86   snprintf(filename, 
sizeof(filename), 
"%s.%x", prefix,
 
   90   PRINTF(
"DB: Reserving %lu bytes in %s\n", size, filename);
 
   92     PRINTF(
"DB: Failed to reserve\n");
 
   99   return fd < 0 ? 
NULL : filename;
 
  104 storage_load(relation_t *rel)
 
  106   PRINTF(
"DB: Opening the tuple file %s\n", rel->tuple_filename);
 
  107   rel->tuple_storage = 
cfs_open(rel->tuple_filename,
 
  109   if(rel->tuple_storage < 0) {
 
  110     PRINTF(
"DB: Failed to open the tuple file\n");
 
  111     return DB_STORAGE_ERROR;
 
  118 storage_unload(relation_t *rel)
 
  120   if(RELATION_HAS_TUPLES(rel)) {
 
  121     PRINTF(
"DB: Unload tuple file %s\n", rel->tuple_filename);
 
  124     rel->tuple_storage = -1;
 
  129 storage_get_relation(relation_t *rel, 
char *name)
 
  134   struct attribute_record record;
 
  139     return DB_STORAGE_ERROR;
 
  142   r = cfs_read(fd, rel->name, 
sizeof(rel->name));
 
  143   if(r != 
sizeof(rel->name)) {
 
  145     PRINTF(
"DB: Failed to read name, got %d of %d bytes\n",
 
  146            r, 
sizeof(rel->name));
 
  147     return DB_STORAGE_ERROR;
 
  150   r = cfs_read(fd, rel->tuple_filename, 
sizeof(rel->tuple_filename));
 
  151   if(r != 
sizeof(rel->name)) {
 
  153     PRINTF(
"DB: Failed to read tuple filename\n");
 
  154     return DB_STORAGE_ERROR;
 
  157   rel->tuple_filename[
sizeof(rel->tuple_filename) - 1] ^= ROW_XOR;
 
  162     r = cfs_read(fd, &record, 
sizeof(record));
 
  166     if(r != 
sizeof(record)) {
 
  167       PRINTF(
"DB: Failed to read attribute record %d (r = %d)\n", i, r);
 
  168       result = DB_STORAGE_ERROR;
 
  172     if(relation_attribute_add(rel, DB_MEMORY, record.name,
 
  173                               record.domain, record.element_size) == 
NULL) {
 
  174       PRINTF(
"DB: Failed to add the attribute %s\n", record.name);
 
  175       result = DB_STORAGE_ERROR;
 
  180   PRINTF(
"DB: Read %d attributes\n", i);
 
  187 storage_put_relation(relation_t *rel)
 
  192   unsigned char *last_byte;
 
  194   PRINTF(
"DB: put_relation(%s)\n", rel->name);
 
  198 #if DB_FEATURE_COFFEE 
  204     return DB_STORAGE_ERROR;
 
  207   r = cfs_write(fd, rel->name, 
sizeof(rel->name));
 
  208   if(r != 
sizeof(rel->name)) {
 
  211     return DB_STORAGE_ERROR;
 
  214   if(rel->tuple_filename[0] == 
'\0') {
 
  215     str = storage_generate_file(
"tuple", DB_COFFEE_RESERVE_SIZE);
 
  219       return DB_STORAGE_ERROR;
 
  222     strncpy(rel->tuple_filename, str, 
sizeof(rel->tuple_filename) - 1);
 
  223     rel->tuple_filename[
sizeof(rel->tuple_filename) - 1] = 
'\0';
 
  231   last_byte = (
unsigned char *)&rel->tuple_filename[
sizeof(rel->tuple_filename) - 1];
 
  232   *last_byte ^= ROW_XOR;
 
  234   r = cfs_write(fd, rel->tuple_filename, 
sizeof(rel->tuple_filename));
 
  236   *last_byte ^= ROW_XOR;
 
  238   if(r != 
sizeof(rel->tuple_filename)) {
 
  241     return DB_STORAGE_ERROR;
 
  244   PRINTF(
"DB: Saved relation %s\n", rel->name);
 
  251 storage_put_attribute(relation_t *rel, attribute_t *attr)
 
  254   struct attribute_record record;
 
  257   PRINTF(
"DB: put_attribute(%s, %s)\n", rel->name, attr->name);
 
  261     return DB_STORAGE_ERROR;
 
  264   memset(&record.name, 0, 
sizeof(record.name));
 
  265   memcpy(record.name, attr->name, 
sizeof(record.name));
 
  266   record.domain = attr->domain;
 
  267   record.element_size = attr->element_size;
 
  268   r = cfs_write(fd, &record, 
sizeof(record));
 
  269   if(r != 
sizeof(record)) {
 
  272     return DB_STORAGE_ERROR;
 
  280 storage_drop_relation(relation_t *rel, 
int remove_tuples)
 
  282   if(remove_tuples && RELATION_HAS_TUPLES(rel)) {
 
  285   return cfs_remove(rel->name) < 0 ? DB_STORAGE_ERROR : DB_OK;
 
  288 #if DB_FEATURE_REMOVE 
  290 storage_rename_relation(
char *old_name, 
char *new_name)
 
  298   result = DB_STORAGE_ERROR;
 
  299   old_fd = new_fd = -1;
 
  303   if(old_fd < 0 || new_fd < 0) {
 
  308     r = cfs_read(old_fd, buf, 
sizeof(buf));
 
  314     if(cfs_write(new_fd, buf, r) != r) {
 
  326   if(result != DB_OK) {
 
  334 storage_get_index(index_t *index, relation_t *rel, attribute_t *attr)
 
  336   char filename[INDEX_NAME_LENGTH];
 
  339   struct index_record record;
 
  342   merge_strings(filename, rel->name, INDEX_NAME_SUFFIX);
 
  346     return DB_STORAGE_ERROR;
 
  349   for(result = DB_STORAGE_ERROR;;) {
 
  350     r = cfs_read(fd, &record, 
sizeof(record));
 
  351     if(r < 
sizeof(record)) {
 
  354     if(strcmp(attr->name, record.attribute_name) == 0) {
 
  355       PRINTF(
"DB: Found the index record for %s.%s: type %d, filename %s\n",
 
  356         rel->name, attr->name, record.type, record.file_name);
 
  357       index->type = record.type;
 
  358       memcpy(index->descriptor_file, record.file_name,
 
  359              sizeof(index->descriptor_file));
 
  370 storage_put_index(index_t *index)
 
  372   char filename[INDEX_NAME_LENGTH];
 
  375   struct index_record record;
 
  378   merge_strings(filename, index->rel->name, INDEX_NAME_SUFFIX);
 
  382     return DB_STORAGE_ERROR;
 
  385   strcpy(record.attribute_name, index->attr->name);
 
  386   memcpy(record.file_name, index->descriptor_file, 
sizeof(record.file_name));
 
  387   record.type = index->type;
 
  390   r = cfs_write(fd, &record, 
sizeof(record));
 
  391   if(r < 
sizeof(record)) {
 
  392     result = DB_STORAGE_ERROR;
 
  394     PRINTF(
"DB: Wrote an index record for %s.%s, type %d\n",
 
  395       index->rel->name, index->attr->name, record.type);
 
  404 storage_get_row(relation_t *rel, tuple_id_t *tuple_id, storage_row_t row)
 
  409   if(DB_ERROR(storage_get_row_amount(rel, &nrows))) {
 
  410     return DB_STORAGE_ERROR;
 
  413   if(*tuple_id >= nrows) {
 
  419     return DB_STORAGE_ERROR;
 
  422   r = cfs_read(rel->tuple_storage, row, rel->row_length);
 
  424     PRINTF(
"DB: Reading failed on fd %d\n", rel->tuple_storage);
 
  425     return DB_STORAGE_ERROR;
 
  428   } 
else if(r < rel->row_length) {
 
  429     PRINTF(
"DB: Incomplete record: %d < %d\n", r, rel->row_length);
 
  430     return DB_STORAGE_ERROR;
 
  433   row[rel->row_length - 1] ^= ROW_XOR;
 
  435   PRINTF(
"DB: Read %d bytes from relation %s\n", rel->row_length, rel->name);
 
  441 storage_put_row(relation_t *rel, storage_row_t row)
 
  446   unsigned char *last_byte;
 
  447 #if DB_FEATURE_INTEGRITY 
  449   char buf[rel->row_length];
 
  453   if(end == (cfs_offset_t)-1) {
 
  454     return DB_STORAGE_ERROR;
 
  457 #if DB_FEATURE_INTEGRITY 
  458   missing_bytes = end % rel->row_length;
 
  459   if(missing_bytes > 0) {
 
  460     memset(buf, 0xff, 
sizeof(buf));
 
  461     r = cfs_write(rel->tuple_storage, buf, 
sizeof(buf));
 
  462     if(r != missing_bytes) {
 
  463       return DB_STORAGE_ERROR;
 
  470   last_byte = row + rel->row_length - 1;
 
  471   *last_byte ^= ROW_XOR;
 
  473   remaining = rel->row_length;
 
  475     r = cfs_write(rel->tuple_storage, row, remaining);
 
  477       PRINTF(
"DB: Failed to store %u bytes\n", remaining);
 
  478       *last_byte ^= ROW_XOR;
 
  479       return DB_STORAGE_ERROR;
 
  483   } 
while(remaining > 0);
 
  485   PRINTF(
"DB: Stored a of %d bytes\n", rel->row_length);
 
  487   *last_byte ^= ROW_XOR;
 
  493 storage_get_row_amount(relation_t *rel, tuple_id_t *amount)
 
  497   if(rel->row_length == 0) {
 
  501     if(offset == (cfs_offset_t)-1) {
 
  502       return DB_STORAGE_ERROR;
 
  505     *amount = (tuple_id_t)(offset / rel->row_length);
 
  512 storage_open(
const char *filename)
 
  517 #if DB_FEATURE_COFFEE 
  526 storage_close(db_storage_id_t fd)
 
  532 storage_read(db_storage_id_t fd,
 
  533              void *buffer, 
unsigned long offset, 
unsigned length)
 
  541     return DB_STORAGE_ERROR;
 
  545     return DB_STORAGE_ERROR;
 
  550     r = cfs_read(fd, ptr, length);
 
  552       return DB_STORAGE_ERROR;
 
  562 storage_write(db_storage_id_t fd,
 
  563               void *buffer, 
unsigned long offset, 
unsigned length)
 
  569     return DB_STORAGE_ERROR;
 
  574     r = cfs_write(fd, ptr, length);
 
  576       return DB_STORAGE_ERROR;
 
int cfs_open(const char *name, int flags)
Open a file. 
 
cfs_offset_t cfs_seek(int fd, cfs_offset_t offset, int whence)
Seek to a specified position in an open file. 
 
#define CFS_WRITE
Specify that cfs_open() should open a file for writing. 
 
#define CFS_COFFEE_IO_FLASH_AWARE
Instruct Coffee that the access pattern to this file is adapted to flash I/O semantics by design...
 
 The storage interface used by the database. 
 
#define NULL
The null pointer. 
 
#define CFS_SEEK_END
Specify that cfs_seek() should compute the offset from the end of the file. 
 
#define CFS_READ
Specify that cfs_open() should open a file for reading. 
 
#define CFS_APPEND
Specify that cfs_open() should append written data to the file rather than overwriting it...
 
int cfs_coffee_reserve(const char *name, cfs_offset_t size)
Reserve space for a file. 
 
 Database configuration options. 
 
int cfs_remove(const char *name)
Remove a file. 
 
int cfs_coffee_set_io_semantics(int fd, unsigned flags)
Set the I/O semantics for accessing a file. 
 
#define CFS_SEEK_SET
Specify that cfs_seek() should compute the offset from the beginning of the file. ...
 
    A set of debugging macros. 
 
 Header for the Coffee file system. 
 
unsigned short random_rand(void)
Generate the next state and return the upper part of it. 
 
void cfs_close(int fd)
Close an open file.