66#define DEBUG DEBUG_NONE
69#define BRANCH_FACTOR 2
70#define BUCKET_SIZE 128
74#if (1 << NODE_DEPTH) != (NODE_LIMIT + 1)
75#error "NODE_DEPTH is set incorrectly."
78#define EMPTY_NODE(node) ((node)->min == 0 && (node)->max == 0)
79#define EMPTY_PAIR(pair) ((pair)->key == 0 && (pair)->value == 0)
81typedef uint16_t maxheap_key_t;
82typedef uint16_t maxheap_value_t;
91typedef struct heap_node heap_node_t;
93struct key_value_pair {
95 maxheap_value_t value;
99 struct key_value_pair pairs[BUCKET_SIZE];
101typedef struct bucket bucket_t;
104 db_storage_id_t heap_storage;
105 db_storage_id_t bucket_storage;
107 uint8_t next_free_slot[NODE_LIMIT];
109typedef struct heap heap_t;
118static struct bucket_cache bucket_cache[DB_HEAP_CACHE_LIMIT];
119MEMB(heaps, heap_t, DB_HEAP_INDEX_LIMIT);
121static struct bucket_cache *get_cache(heap_t *,
int);
122static struct bucket_cache *get_cache_free(
void);
123static void invalidate_cache(
void);
124static maxheap_key_t transform_key(maxheap_key_t);
125static int heap_read(heap_t *,
int, heap_node_t *);
126static int heap_write(heap_t *,
int, heap_node_t *);
127static int heap_insert(heap_t *, maxheap_key_t, maxheap_key_t);
128static int heap_find(heap_t *, maxheap_key_t key,
int *iterator);
130static void heap_print(heap_t *);
132static int bucket_read(heap_t *,
int, bucket_t *);
133static struct bucket_cache *bucket_load(heap_t *,
int);
134static int bucket_append(heap_t *,
int,
struct key_value_pair *);
135static int bucket_split(heap_t *,
int);
137static db_result_t create(index_t *);
138static db_result_t destroy(index_t *);
139static db_result_t load(index_t *);
140static db_result_t release(index_t *);
141static db_result_t insert(index_t *, attribute_value_t *, tuple_id_t);
142static db_result_t
delete(index_t *, attribute_value_t *);
143static tuple_id_t get_next(index_iterator_t *);
145index_api_t index_maxheap = {
157static struct bucket_cache *
158get_cache(heap_t *heap,
int bucket_id)
162 for(i = 0; i < DB_HEAP_CACHE_LIMIT; i++) {
163 if(bucket_cache[i].heap == heap && bucket_cache[i].bucket_id == bucket_id) {
164 return &bucket_cache[i];
170static struct bucket_cache *
175 for(i = 0; i < DB_HEAP_CACHE_LIMIT; i++) {
176 if(bucket_cache[i].heap == NULL) {
177 return &bucket_cache[i];
184invalidate_cache(
void)
188 for(i = 0; i < DB_HEAP_CACHE_LIMIT; i++) {
189 if(bucket_cache[i].heap != NULL) {
190 bucket_cache[i].heap = NULL;
197transform_key(maxheap_key_t key)
199 return crc16_data((
const uint8_t *)&key,
sizeof(key), 0);
203heap_read(heap_t *heap,
int bucket_id, heap_node_t *node)
205 if(DB_ERROR(storage_read(heap->heap_storage, node,
206 DB_MAX_FILENAME_LENGTH + (
unsigned long)bucket_id *
sizeof(*node),
sizeof(*node)))) {
214heap_write(heap_t *heap,
int bucket_id, heap_node_t *node)
216 if(DB_ERROR(storage_write(heap->heap_storage, node,
217 DB_MAX_FILENAME_LENGTH + (
unsigned long)bucket_id *
sizeof(*node),
sizeof(*node)))) {
225heap_insert(heap_t *heap, maxheap_key_t min, maxheap_key_t max)
230 PRINTF(
"DB: Insert node (%ld,%ld) into the heap\n", (
long)min, (
long)max);
236 for(i = 0; i < NODE_LIMIT;) {
237 if(heap_read(heap, i, &node) == 0) {
238 PRINTF(
"DB: Failed to read heap node %d\n", i);
242 if(EMPTY_NODE(&node)) {
245 if(heap_write(heap, i, &node) == 0) {
246 PRINTF(
"DB: Failed to write heap node %d\n", i);
250 }
else if(node.min <= min && max <= node.max) {
251 i = BRANCH_FACTOR * i + 1;
257 PRINTF(
"DB: No more nodes available\n");
262heap_find(heap_t *heap, maxheap_key_t key,
int *iterator)
264 maxheap_key_t hashed_key;
267 static heap_node_t node;
269 hashed_key = transform_key(key);
271 for(i = *iterator; i < NODE_LIMIT;) {
272 if(heap_read(heap, i, &node) == 0) {
275 if(EMPTY_NODE(&node)) {
277 }
else if(node.min <= hashed_key && hashed_key <= node.max) {
278 first_child = BRANCH_FACTOR * i + 1;
280 if(first_child >= NODE_LIMIT) {
283 *iterator = first_child;
295heap_print(heap_t *heap)
305 branch_amount = BRANCH_FACTOR;
308 if(heap_read(heap, i, &node) == 0 || EMPTY_NODE(&node)) {
312 for(j = 0; j < level_count; j++) {
315 PRINTF(
"(%ld,%ld)\n", (
long)node.min, (
long)node.max);
316 if(level_count == 0) {
318 }
else if(branch_count + 1 == branch_amount) {
321 branch_amount = branch_amount * BRANCH_FACTOR;
330bucket_read(heap_t *heap,
int bucket_id, bucket_t *bucket)
334 if(heap->next_free_slot[bucket_id] == 0) {
337 size = heap->next_free_slot[bucket_id];
340 size *=
sizeof(
struct key_value_pair);
342 if(DB_ERROR(storage_read(heap->bucket_storage, bucket,
343 (
unsigned long)bucket_id *
sizeof(*bucket), size))) {
350static struct bucket_cache *
351bucket_load(heap_t *heap,
int bucket_id)
354 struct bucket_cache *cache;
356 cache = get_cache(heap, bucket_id);
361 cache = get_cache_free();
364 cache = get_cache_free();
370 if(bucket_read(heap, bucket_id, &cache->bucket) == 0) {
375 cache->bucket_id = bucket_id;
377 if(heap->next_free_slot[bucket_id] == 0) {
378 for(i = 0; i < BUCKET_SIZE; i++) {
379 if(EMPTY_PAIR(&cache->bucket.pairs[i])) {
384 heap->next_free_slot[bucket_id] = i;
387 PRINTF(
"DB: Loaded bucket %d, the next free slot is %u\n", bucket_id,
388 (
unsigned)heap->next_free_slot[bucket_id]);
394bucket_append(heap_t *heap,
int bucket_id,
struct key_value_pair *pair)
396 unsigned long offset;
398 if(heap->next_free_slot[bucket_id] >= BUCKET_SIZE) {
399 PRINTF(
"DB: Invalid write attempt to the full bucket %d\n", bucket_id);
403 offset = (
unsigned long)bucket_id *
sizeof(bucket_t);
404 offset += heap->next_free_slot[bucket_id] *
sizeof(
struct key_value_pair);
406 if(DB_ERROR(storage_write(heap->bucket_storage, pair, offset,
sizeof(*pair)))) {
410 heap->next_free_slot[bucket_id]++;
416bucket_split(heap_t *heap,
int bucket_id)
420 int small_bucket_index;
421 int large_bucket_index;
423 if(heap_read(heap, bucket_id, &node) == 0) {
427 mean = node.min + ((node.max - node.min) / 2);
429 PRINTF(
"DB: Split bucket %d (%ld, %ld) at mean value %ld\n", bucket_id,
430 (
long)node.min, (
long)node.max, (
long)mean);
432 small_bucket_index = heap_insert(heap, node.min, mean);
433 if(small_bucket_index < 0) {
437 large_bucket_index = heap_insert(heap, mean + 1, node.max);
438 if(large_bucket_index < 0) {
447insert_item(heap_t *heap, maxheap_key_t key, maxheap_value_t value)
450 int bucket_id, last_good_bucket_id;
451 struct key_value_pair pair;
453 for(heap_iterator = 0, last_good_bucket_id = -1;;) {
454 bucket_id = heap_find(heap, key, &heap_iterator);
458 last_good_bucket_id = bucket_id;
460 bucket_id = last_good_bucket_id;
463 PRINTF(
"DB: No bucket for key %ld\n", (
long)key);
470 if(heap->next_free_slot[bucket_id] == BUCKET_SIZE) {
471 PRINTF(
"DB: Bucket %d is full\n", bucket_id);
472 if(bucket_split(heap, bucket_id) == 0) {
477 bucket_id = heap_find(heap, key, &heap_iterator);
483 if(bucket_append(heap, bucket_id, &pair) == 0) {
487 PRINTF(
"DB: Inserted key %ld (hash %ld) into the heap at bucket_id %d\n",
488 (
long)key, (
long)transform_key(key), bucket_id);
494create(index_t *index)
496 char heap_filename[DB_MAX_FILENAME_LENGTH];
497 char bucket_filename[DB_MAX_FILENAME_LENGTH];
504 bucket_filename[0] =
'\0';
508 filename = storage_generate_file(
"heap",
509 (
unsigned long)NODE_LIMIT *
sizeof(heap_node_t));
510 if(filename == NULL) {
511 PRINTF(
"DB: Failed to generate a heap file\n");
512 return DB_INDEX_ERROR;
515 memcpy(index->descriptor_file, filename,
516 sizeof(index->descriptor_file));
518 PRINTF(
"DB: Generated the heap file \"%s\" using %lu bytes of space\n",
519 index->descriptor_file, (
unsigned long)NODE_LIMIT *
sizeof(heap_node_t));
521 index->opaque_data = heap =
memb_alloc(&heaps);
523 PRINTF(
"DB: Failed to allocate a heap\n");
524 result = DB_ALLOCATION_ERROR;
527 heap->heap_storage = -1;
528 heap->bucket_storage = -1;
531 filename = storage_generate_file(
"bucket",
532 (
unsigned long)NODE_LIMIT *
sizeof(bucket_t));
533 if(filename == NULL) {
534 PRINTF(
"DB: Failed to generate a bucket file\n");
535 result = DB_INDEX_ERROR;
538 memcpy(bucket_filename, filename,
sizeof(bucket_filename));
540 PRINTF(
"DB: Generated the bucket file \"%s\" using %lu bytes of space\n",
541 bucket_filename, (
unsigned long)NODE_LIMIT *
sizeof(bucket_t));
544 memset(&heap->next_free_slot, 0,
sizeof(heap->next_free_slot));
546 heap->heap_storage = storage_open(index->descriptor_file);
547 heap->bucket_storage = storage_open(bucket_filename);
548 if(heap->heap_storage < 0 || heap->bucket_storage < 0) {
549 result = DB_STORAGE_ERROR;
553 if(DB_ERROR(storage_write(heap->heap_storage, &bucket_filename, 0,
554 sizeof(bucket_filename)))) {
555 result = DB_STORAGE_ERROR;
559 if(heap_insert(heap, KEY_MIN, KEY_MAX) < 0) {
560 PRINTF(
"DB: Heap insertion error\n");
561 result = DB_INDEX_ERROR;
565 PRINTF(
"DB: Created a heap index\n");
569 if(result != DB_OK) {
571 storage_close(heap->bucket_storage);
572 storage_close(heap->heap_storage);
575 if(index->descriptor_file[0] !=
'\0') {
577 index->descriptor_file[0] =
'\0';
579 if(bucket_filename[0] !=
'\0') {
587destroy(index_t *index)
590 return DB_INDEX_ERROR;
598 char bucket_file[DB_MAX_FILENAME_LENGTH];
600 index->opaque_data = heap =
memb_alloc(&heaps);
602 PRINTF(
"DB: Failed to allocate a heap\n");
603 return DB_ALLOCATION_ERROR;
606 fd = storage_open(index->descriptor_file);
608 return DB_STORAGE_ERROR;
611 if(storage_read(fd, bucket_file, 0,
sizeof(bucket_file)) !=
612 sizeof(bucket_file)) {
614 return DB_STORAGE_ERROR;
619 heap->heap_storage = storage_open(index->descriptor_file);
620 heap->bucket_storage = storage_open(bucket_file);
622 memset(&heap->next_free_slot, 0,
sizeof(heap->next_free_slot));
624 PRINTF(
"DB: Loaded max-heap index from file %s and bucket file %s\n",
625 index->descriptor_file, bucket_file);
631release(index_t *index)
635 heap = index->opaque_data;
637 storage_close(heap->bucket_storage);
638 storage_close(heap->heap_storage);
640 return DB_INDEX_ERROR;
644insert(index_t *index, attribute_value_t *key, tuple_id_t value)
649 heap = (heap_t *)index->opaque_data;
651 long_key = db_value_to_long(key);
653 if(insert_item(heap, (maxheap_key_t)long_key,
654 (maxheap_value_t)value) == 0) {
655 PRINTF(
"DB: Failed to insert key %ld into a max-heap index\n", long_key);
656 return DB_INDEX_ERROR;
662delete(index_t *index, attribute_value_t *value)
664 return DB_INDEX_ERROR;
668get_next(index_iterator_t *iterator)
670 struct iteration_cache {
671 index_iterator_t *index_iterator;
673 tuple_id_t found_items;
675 int visited_buckets[NODE_DEPTH];
678 static struct iteration_cache cache;
682 int tmp_heap_iterator;
684 struct bucket_cache *bcache;
685 uint8_t next_free_slot;
687 heap = (heap_t *)iterator->index->opaque_data;
688 key = VALUE_INT(&iterator->min_value);
690 if(cache.index_iterator != iterator || iterator->next_item_no == 0) {
692 cache.end = NODE_DEPTH - 1;
693 cache.found_items = cache.start = 0;
694 cache.index_iterator = iterator;
698 for(i = tmp_heap_iterator = 0; i < NODE_DEPTH; i++) {
699 cache.visited_buckets[i] = heap_find(heap, key, &tmp_heap_iterator);
700 if(cache.visited_buckets[i] < 0) {
705 cache.heap_iterator = cache.end;
714 for(; cache.heap_iterator >= 0; cache.heap_iterator--) {
715 bucket_id = cache.visited_buckets[cache.heap_iterator];
717 PRINTF(
"DB: Find key %lu in bucket %d\n", (
unsigned long)key, bucket_id);
719 if((bcache = bucket_load(heap, bucket_id)) == NULL) {
720 PRINTF(
"DB: Failed to load bucket %d\n", bucket_id);
721 return INVALID_TUPLE;
726 next_free_slot = heap->next_free_slot[bucket_id];
727 for(i = cache.start; i < next_free_slot; i++) {
728 if(bcache->bucket.pairs[i].key == key) {
729 if(cache.found_items++ == iterator->next_item_no) {
730 iterator->next_item_no++;
732 PRINTF(
"DB: Found key %ld with value %lu\n", (
long)key,
733 (
unsigned long)bcache->bucket.pairs[i].value);
734 return (tuple_id_t)bcache->bucket.pairs[i].value;
740 if(VALUE_INT(&iterator->min_value) == VALUE_INT(&iterator->max_value)) {
741 PRINTF(
"DB: Could not find key %ld in the index\n", (
long)key);
742 return INVALID_TUPLE;
745 iterator->next_item_no = 0;
746 VALUE_INT(&iterator->min_value)++;
748 return get_next(iterator);
Header for the Coffee file system.
Header file for the CRC16 calculcation.
Database configuration options.
int cfs_remove(const char *name)
Remove a file.
unsigned short crc16_data(const unsigned char *data, int len, unsigned short acc)
Calculate the CRC16 over a data area.
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
#define MEMB(name, structure, num)
Declare a memory block.
static void start(void)
Start measurement.
Memory block allocation routines.
Declarations for the result acquisition API.
The storage interface used by the database.
A set of debugging macros for the IP stack.