43#include "lib/random.h"
45#define DEBUG DEBUG_NONE
51struct 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))
72merge_strings(
char *dest,
size_t dest_size,
char *prefix,
char *suffix)
74 size_t prefix_len = strlen(prefix);
75 size_t suffix_len = strlen(suffix);
77 if(dest_size < prefix_len + suffix_len + 1) {
81 memcpy(dest, prefix, prefix_len);
82 memcpy(dest + prefix_len, suffix, suffix_len);
83 dest[prefix_len + suffix_len] =
'\0';
89storage_generate_file(
char *prefix,
unsigned long size)
91 static char filename[ATTRIBUTE_NAME_LENGTH +
sizeof(
".ffff")];
96 snprintf(filename,
sizeof(filename),
"%s.%x", prefix,
100 PRINTF(
"DB: Reserving %lu bytes in %s\n", size, filename);
102 PRINTF(
"DB: Failed to reserve\n");
109 return fd < 0 ? NULL : filename;
114storage_load(relation_t *rel)
116 PRINTF(
"DB: Opening the tuple file %s\n", rel->tuple_filename);
117 rel->tuple_storage =
cfs_open(rel->tuple_filename,
119 if(rel->tuple_storage < 0) {
120 PRINTF(
"DB: Failed to open the tuple file\n");
121 return DB_STORAGE_ERROR;
128storage_unload(relation_t *rel)
130 if(RELATION_HAS_TUPLES(rel)) {
131 PRINTF(
"DB: Unload tuple file %s\n", rel->tuple_filename);
134 rel->tuple_storage = -1;
139storage_get_relation(relation_t *rel,
char *name)
144 struct attribute_record record;
149 return DB_STORAGE_ERROR;
152 r =
cfs_read(fd, rel->name,
sizeof(rel->name));
153 if(r !=
sizeof(rel->name)) {
155 PRINTF(
"DB: Failed to read name, got %d of %d bytes\n",
156 r,
sizeof(rel->name));
157 return DB_STORAGE_ERROR;
160 r =
cfs_read(fd, rel->tuple_filename,
sizeof(rel->tuple_filename));
161 if(r !=
sizeof(rel->name)) {
163 PRINTF(
"DB: Failed to read tuple filename\n");
164 return DB_STORAGE_ERROR;
167 rel->tuple_filename[
sizeof(rel->tuple_filename) - 1] ^= ROW_XOR;
172 r =
cfs_read(fd, &record,
sizeof(record));
176 if(r !=
sizeof(record)) {
177 PRINTF(
"DB: Failed to read attribute record %d (r = %d)\n", i, r);
178 result = DB_STORAGE_ERROR;
182 if(relation_attribute_add(rel, DB_MEMORY, record.name,
183 record.domain, record.element_size) == NULL) {
184 PRINTF(
"DB: Failed to add the attribute %s\n", record.name);
185 result = DB_STORAGE_ERROR;
191 PRINTF(
"DB: Read %d attributes\n", i);
198storage_put_relation(relation_t *rel)
203 unsigned char *last_byte;
205 PRINTF(
"DB: put_relation(%s)\n", rel->name);
215 return DB_STORAGE_ERROR;
218 r =
cfs_write(fd, rel->name,
sizeof(rel->name));
219 if(r !=
sizeof(rel->name)) {
222 return DB_STORAGE_ERROR;
225 if(rel->tuple_filename[0] ==
'\0') {
226 str = storage_generate_file(
"tuple", DB_COFFEE_RESERVE_SIZE);
230 return DB_STORAGE_ERROR;
233 strncpy(rel->tuple_filename, str,
sizeof(rel->tuple_filename) - 1);
234 rel->tuple_filename[
sizeof(rel->tuple_filename) - 1] =
'\0';
242 last_byte = (
unsigned char *)&rel->tuple_filename[
sizeof(rel->tuple_filename) - 1];
243 *last_byte ^= ROW_XOR;
245 r =
cfs_write(fd, rel->tuple_filename,
sizeof(rel->tuple_filename));
247 *last_byte ^= ROW_XOR;
249 if(r !=
sizeof(rel->tuple_filename)) {
252 return DB_STORAGE_ERROR;
255 PRINTF(
"DB: Saved relation %s\n", rel->name);
262storage_put_attribute(relation_t *rel, attribute_t *attr)
265 struct attribute_record record;
268 PRINTF(
"DB: put_attribute(%s, %s)\n", rel->name, attr->name);
272 return DB_STORAGE_ERROR;
275 memset(&record.name, 0,
sizeof(record.name));
276 memcpy(record.name, attr->name,
sizeof(record.name));
277 record.domain = attr->domain;
278 record.element_size = attr->element_size;
279 r =
cfs_write(fd, &record,
sizeof(record));
280 if(r !=
sizeof(record)) {
283 return DB_STORAGE_ERROR;
291storage_drop_relation(relation_t *rel,
int remove_tuples)
293 if(remove_tuples && RELATION_HAS_TUPLES(rel)) {
296 return cfs_remove(rel->name) < 0 ? DB_STORAGE_ERROR : DB_OK;
301storage_rename_relation(
char *old_name,
char *new_name)
309 result = DB_STORAGE_ERROR;
310 old_fd = new_fd = -1;
314 if(old_fd < 0 || new_fd < 0) {
319 r =
cfs_read(old_fd, buf,
sizeof(buf));
337 if(result != DB_OK) {
345storage_get_index(index_t *index, relation_t *rel, attribute_t *attr)
347 char filename[INDEX_NAME_LENGTH + 1];
350 struct index_record record;
353 if(!merge_strings(filename,
sizeof(filename), rel->name, INDEX_NAME_SUFFIX)) {
354 return DB_NAME_ERROR;
359 return DB_STORAGE_ERROR;
362 for(result = DB_STORAGE_ERROR;;) {
363 r =
cfs_read(fd, &record,
sizeof(record));
364 if(r <
sizeof(record)) {
367 if(strcmp(attr->name, record.attribute_name) == 0) {
368 PRINTF(
"DB: Found the index record for %s.%s: type %d, filename %s\n",
369 rel->name, attr->name, record.type, record.file_name);
370 index->type = record.type;
371 memcpy(index->descriptor_file, record.file_name,
372 sizeof(index->descriptor_file));
383storage_put_index(index_t *index)
385 char filename[INDEX_NAME_LENGTH + 1];
388 struct index_record record;
391 if(!merge_strings(filename,
sizeof(filename), index->rel->name,
392 INDEX_NAME_SUFFIX)) {
393 return DB_NAME_ERROR;
398 return DB_STORAGE_ERROR;
401 strcpy(record.attribute_name, index->attr->name);
402 memcpy(record.file_name, index->descriptor_file,
sizeof(record.file_name));
403 record.type = index->type;
406 r =
cfs_write(fd, &record,
sizeof(record));
407 if(r <
sizeof(record)) {
408 result = DB_STORAGE_ERROR;
410 PRINTF(
"DB: Wrote an index record for %s.%s, type %d\n",
411 index->rel->name, index->attr->name, record.type);
420storage_get_row(relation_t *rel, tuple_id_t *tuple_id, storage_row_t row)
425 if(DB_ERROR(storage_get_row_amount(rel, &nrows))) {
426 return DB_STORAGE_ERROR;
429 if(*tuple_id >= nrows) {
435 return DB_STORAGE_ERROR;
438 r =
cfs_read(rel->tuple_storage, row, rel->row_length);
440 PRINTF(
"DB: Reading failed on fd %d\n", rel->tuple_storage);
441 return DB_STORAGE_ERROR;
444 }
else if(r < rel->row_length) {
445 PRINTF(
"DB: Incomplete record: %d < %d\n", r, rel->row_length);
446 return DB_STORAGE_ERROR;
449 row[rel->row_length - 1] ^= ROW_XOR;
451 PRINTF(
"DB: Read %d bytes from relation %s\n", rel->row_length, rel->name);
457storage_put_row(relation_t *rel, storage_row_t row)
462 unsigned char *last_byte;
463#if DB_FEATURE_INTEGRITY
465 char buf[rel->row_length];
470 return DB_STORAGE_ERROR;
473#if DB_FEATURE_INTEGRITY
474 missing_bytes = end % rel->row_length;
475 if(missing_bytes > 0) {
476 memset(buf, 0xff,
sizeof(buf));
477 r =
cfs_write(rel->tuple_storage, buf,
sizeof(buf));
478 if(r != missing_bytes) {
479 return DB_STORAGE_ERROR;
486 last_byte = row + rel->row_length - 1;
487 *last_byte ^= ROW_XOR;
489 remaining = rel->row_length;
491 r =
cfs_write(rel->tuple_storage, row, remaining);
493 PRINTF(
"DB: Failed to store %u bytes\n", remaining);
494 *last_byte ^= ROW_XOR;
495 return DB_STORAGE_ERROR;
499 }
while(remaining > 0);
501 PRINTF(
"DB: Stored a of %d bytes\n", rel->row_length);
503 *last_byte ^= ROW_XOR;
509storage_get_row_amount(relation_t *rel, tuple_id_t *amount)
513 if(rel->row_length == 0) {
518 return DB_STORAGE_ERROR;
521 *amount = (tuple_id_t)(offset / rel->row_length);
528storage_open(
const char *filename)
542storage_close(db_storage_id_t fd)
548storage_read(db_storage_id_t fd,
549 void *buffer,
unsigned long offset,
unsigned length)
557 return DB_STORAGE_ERROR;
561 return DB_STORAGE_ERROR;
568 return DB_STORAGE_ERROR;
578storage_write(db_storage_id_t fd,
579 void *buffer,
unsigned long offset,
unsigned length)
585 return DB_STORAGE_ERROR;
592 return DB_STORAGE_ERROR;
Header for the Coffee file system.
Database configuration options.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
#define CFS_READ
Specify that cfs_open() should open a file for reading.
int cfs_read(int f, void *buf, unsigned int len)
Read data from an open file.
int cfs_coffee_reserve(const char *name, cfs_offset_t size)
Reserve space for a file.
#define CFS_APPEND
Specify that cfs_open() should append written data to the file rather than overwriting it.
#define CFS_COFFEE_IO_FLASH_AWARE
Instruct Coffee that the access pattern to this file is adapted to flash I/O semantics by design,...
int cfs_remove(const char *name)
Remove a file.
int cfs_open(const char *n, int f)
Open a file.
#define CFS_SEEK_SET
Specify that cfs_seek() should compute the offset from the beginning of the file.
#define CFS_WRITE
Specify that cfs_open() should open a file for writing.
cfs_offset_t cfs_seek(int f, cfs_offset_t o, int w)
Seek to a specified position in an open file.
#define CFS_SEEK_END
Specify that cfs_seek() should compute the offset from the end of the file.
int cfs_write(int f, const void *buf, unsigned int len)
Write data to an open file.
void cfs_close(int f)
Close an open file.
int cfs_coffee_set_io_semantics(int fd, unsigned flags)
Set the I/O semantics for accessing a file.
int cfs_offset_t
CFS directory entry name length.
The storage interface used by the database.
A set of debugging macros for the IP stack.