mirror of
https://github.com/etcd-io/bbolt.git
synced 2025-05-31 11:42:30 +00:00
151 lines
3.2 KiB
Go
151 lines
3.2 KiB
Go
package c
|
|
|
|
/*
|
|
|
|
#define MAX_DEPTH 100
|
|
#define BRANCH_PAGE 1
|
|
|
|
// These types MUST have the same layout as their corresponding Go types
|
|
|
|
typedef unsigned long long pageid;
|
|
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 pgid;
|
|
} 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 {
|
|
void *element;
|
|
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;
|
|
elemid[MAX_DEPTH] stack;
|
|
unsigned int stackp;
|
|
} bolt_cursor;
|
|
|
|
// public functions
|
|
|
|
void bolt_cursor_init(bolt_cursor* c, void *data, size_t pgsz, pgid root) {
|
|
c->data = data;
|
|
c->pgid = pgid;
|
|
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 = page(c, c->pgid);
|
|
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++;
|
|
}
|
|
// increment element pointer
|
|
if(ref->page | BRANCH_PAGE)
|
|
ref->element += sizeof(branch_elem);
|
|
else
|
|
ref->element += sizeof(leaf_elem);
|
|
|
|
// get current leaf element
|
|
return leaf_element(c, key, value);
|
|
}
|
|
|
|
// int bolt_cursor_seek(bolt_cursor* c, bolt_val key, bolt_val *actual_key, bolt_val *value)
|
|
|
|
// private functions
|
|
|
|
page* page(bolt_cursor* c, pgid id) {
|
|
return (page*)(c->data + (c->pgsz * id));
|
|
}
|
|
|
|
branch_elem* branch_page_element(page* p, elemid index) {
|
|
return p + sizeof(page) + index * sizeof(branch_elem);
|
|
}
|
|
|
|
leaf_elem* leaf_page_element(page* p, elemid index) {
|
|
return 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;
|
|
for(ref->page->flags | BRANCH_PAGE) {
|
|
branch = branch_page_element(ref->page,ref->index);
|
|
c->stackp++;
|
|
ref = &c->stack[c->stackp];
|
|
ref->index = 0;
|
|
ref->element = branch;
|
|
ref->page = page(c, branch->pgid);
|
|
};
|
|
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;
|
|
}
|
|
|
|
*/
|
|
import "C"
|
|
import "github.com/boltdb/bolt"
|
|
|
|
func NewCursor(b *bolt.Bucket) *C.bolt_cursor {
|
|
data := (*C.void)(&b.tx.db.data[0])
|
|
pgsz := (C.size_t)(b.tx.db.pageSize)
|
|
cursor := new(C.bolt_cursor)
|
|
C.bolt_cursor_init(cursor, data, pgsz, (C.pgid)(b.root))
|
|
return cursor
|
|
}
|