bbolt/c/cursor.go

164 lines
3.5 KiB
Go

package c
/*
#include <stdint.h>
#include <stdlib.h>
#define MAX_DEPTH 100
#define BRANCH_PAGE 1
// These types MUST have the same layout as their corresponding Go types
typedef unsigned long long pgid;
typedef unsigned short elemid;
typedef struct page {
pgid id;
unsigned short flags;
elemid count;
unsigned long overflow;
} page;
typedef struct branch_elem {
unsigned long pos;
unsigned long ksize;
pgid page;
} branch_elem;
typedef struct leaf_elem {
unsigned long flags;
unsigned long pos;
unsigned long ksize;
unsigned long vsize;
} leaf_elem;
// private types
typedef struct elem_ref {
page *page;
elemid index;
} elem_ref;
// public types
typedef struct bolt_val {
uint32_t size;
void *data;
} bolt_val;
typedef struct bolt_cursor {
void *data;
pgid root;
size_t pgsz;
unsigned int stackp;
elem_ref stack[MAX_DEPTH];
} bolt_cursor;
// int bolt_cursor_seek(bolt_cursor *c, bolt_val *key, bolt_val *actual_key, bolt_val *value)
// private functions
page *get_page(bolt_cursor *c, pgid id) {
return (page *)(c->data + (c->pgsz * id));
}
branch_elem *branch_page_element(page *p, elemid index) {
return (branch_elem*)(p + sizeof(page) + index * sizeof(branch_elem));
}
leaf_elem *leaf_page_element(page *p, elemid index) {
return (leaf_elem*)(p + sizeof(page) + index * sizeof(leaf_elem));
}
// return current leaf element
// if stack points at a branch page descend down to the first elemenet
// of the first leaf page
int leaf_element(bolt_cursor *c, bolt_val *key, bolt_val *value) {
elem_ref *ref = &(c->stack[c->stackp]);
branch_elem *branch;
while (ref->page->flags | BRANCH_PAGE) {
branch = branch_page_element(ref->page,ref->index);
c->stackp++;
ref = &c->stack[c->stackp];
ref->index = 0;
ref->page = get_page(c, branch->page);
};
set_key_value(leaf_page_element(ref->page,ref->index), key, value);
return 0;
}
set_key_value(leaf_elem *leaf, bolt_val *key, bolt_val *value) {
key->size = leaf->ksize;
key->data = leaf + leaf->pos;
value->size = leaf->vsize;
value->data = key->data + key->size;
}
// public functions
void bolt_cursor_init(bolt_cursor *c, void *data, size_t pgsz, pgid root) {
c->data = data;
c->root = root;
c->pgsz = pgsz;
}
int bolt_cursor_first(bolt_cursor *c, bolt_val *key, bolt_val *value) {
leaf_elem *leaf;
elem_ref *ref;
// reset stack to initial state
c->stackp = 0;
ref = &(c->stack[c->stackp]);
ref->page = get_page(c, c->root);
ref->index = 0;
// get current leaf element
return leaf_element(c, key, value);
}
int bolt_cursor_next(bolt_cursor *c, bolt_val *key, bolt_val *value) {
elem_ref *ref = &c->stack[c->stackp];
// increment element index
ref->index++;
// if we're past last element pop the stack and repeat
while (ref->index >= ref->page->count ) {
c->stackp--;
ref = &c->stack[c->stackp];
ref->index++;
};
// get current leaf element
return leaf_element(c, key, value);
}
*/
import "C"
import (
"unsafe"
"github.com/boltdb/bolt"
)
type bolt_cursor *C.bolt_cursor
func NewCursor(b *bolt.Bucket) bolt_cursor {
data, pgsz := b.Tx().DB().RawData()
cursor := new(C.bolt_cursor)
C.bolt_cursor_init(cursor, unsafe.Pointer(&data[0]), (C.size_t)(pgsz), (C.pgid)(b.Root()))
return cursor
}
func first(c bolt_cursor) (key, value []byte) {
var k, v C.bolt_val
C.bolt_cursor_first(c, &k, &v)
return C.GoBytes(k.data, C.int(k.size)), C.GoBytes(v.data, C.int(v.size))
}
func next(c bolt_cursor) (key, value []byte) {
var k, v C.bolt_val
C.bolt_cursor_next(c, &k, &v)
return C.GoBytes(k.data, C.int(k.size)), C.GoBytes(v.data, C.int(v.size))
}