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.