diff options
-rw-r--r-- | bucket.go | 21 | ||||
-rw-r--r-- | const.go | 15 | ||||
-rw-r--r-- | cursor.go | 44 | ||||
-rw-r--r-- | db.go | 19 | ||||
-rw-r--r-- | error.go | 30 | ||||
-rw-r--r-- | info.go | 10 | ||||
-rw-r--r-- | meta.go | 32 | ||||
-rw-r--r-- | node.go | 40 | ||||
-rw-r--r-- | page.go | 44 | ||||
-rw-r--r-- | reader.go | 5 | ||||
-rw-r--r-- | stat.go | 10 | ||||
-rw-r--r-- | transaction.go | 33 | ||||
-rw-r--r-- | warn.go | 14 | ||||
-rw-r--r-- | xcursor.go | 8 |
14 files changed, 325 insertions, 0 deletions
diff --git a/bucket.go b/bucket.go new file mode 100644 index 0000000..16f8be3 --- /dev/null +++ b/bucket.go @@ -0,0 +1,21 @@ +package bolt + +// TODO: #define MDB_VALID 0x8000 /**< DB handle is valid, for me_dbflags */ +// TODO: #define PERSISTENT_FLAGS (0xffff & ~(MDB_VALID)) +// TODO: #define VALID_FLAGS (MDB_REVERSEKEY|MDB_DUPSORT|MDB_INTEGERKEY|MDB_DUPFIXED|MDB_INTEGERDUP|MDB_REVERSEDUP|MDB_CREATE) +// TODO: #define FREE_DBI 0 +// TODO: #define MAIN_DBI 1 + +type Bucket interface { +} + +type bucket struct { + pad int + flags int + depth int + branchPageCount int + leafPageCount int + overflowPageCount int + entryCount int + rootID int +} diff --git a/const.go b/const.go new file mode 100644 index 0000000..3bbb8dc --- /dev/null +++ b/const.go @@ -0,0 +1,15 @@ +package bolt + +const Version = 1 + +const magic int32 = 0xBEEFC0DE + +const ( + MaxKeySize = 511 + MaxDataSize = 0xffffffff +) + +const ( + DefaultMapSize = 1048576 + DefaultReaderCount = 126 +) diff --git a/cursor.go b/cursor.go new file mode 100644 index 0000000..8399b88 --- /dev/null +++ b/cursor.go @@ -0,0 +1,44 @@ +package bolt + +// TODO: #define CURSOR_STACK 32 + +// TODO: #define C_INITIALIZED 0x01 /**< cursor has been initialized and is valid */ +// TODO: #define C_EOF 0x02 /**< No more data */ +// TODO: #define C_SUB 0x04 /**< Cursor is a sub-cursor */ +// TODO: #define C_DEL 0x08 /**< last op was a cursor_del */ +// TODO: #define C_SPLITTING 0x20 /**< Cursor is in page_split */ +// TODO: #define C_UNTRACK 0x40 /**< Un-track cursor when closing */ + +type Cursor interface { + First() error + FirstDup() error + Get() ([]byte, []byte, error) + GetRange() ([]byte, []byte, error) + Current() ([]byte, []byte, error) + Last() + LastDup() + Next() ([]byte, []byte, error) + NextDup() ([]byte, []byte, error) + NextNoDup() ([]byte, []byte, error) + Prev() ([]byte, []byte, error) + PrevDup() ([]byte, []byte, error) + PrevNoDup() ([]byte, []byte, error) + Set() ([]byte, []byte, error) + SetRange() ([]byte, []byte, error) +} + +type cursor struct { + flags int + next *cursor + backup *cursor + xcursor *xcursor + transaction *transaction + bucketId int + bucket *bucket + bucketx *bucketx + bucketFlag int + snum int + top int + page []*page + ki []int /**< stack of page indices */ +} @@ -0,0 +1,19 @@ +package bolt + +const ( + NoSync = iota + NoMetaSync + DupSort + IntegerKey + IntegerDupKey +) + +type DB interface { +} + +type db struct { +} + +func NewDB() DB { + return &db{} +} diff --git a/error.go b/error.go new file mode 100644 index 0000000..caed282 --- /dev/null +++ b/error.go @@ -0,0 +1,30 @@ +package bolt + +var ( + KeyExistError = &Error{"Key/data pair already exists"} + NotFoundError = &Error{"No matching key/data pair found"} + PageNotFoundError = &Error{"Requested page not found"} + CorruptedError = &Error{"Located page was wrong type"} + PanicError = &Error{"Update of meta page failed"} + VersionMismatchError = &Error{"Database environment version mismatch"} + InvalidError = &Error{"File is not an MDB file"} + MapFullError = &Error{"Environment mapsize limit reached"} + BucketFullError = &Error{"Environment maxdbs limit reached"} + ReadersFullError = &Error{"Environment maxreaders limit reached"} + TransactionFullError = &Error{"Transaction has too many dirty pages - transaction too big"} + CursorFullError = &Error{"Internal error - cursor stack limit reached"} + PageFullError = &Error{"Internal error - page has no more space"} + MapResizedError = &Error{"Database contents grew beyond environment mapsize"} + IncompatibleError = &Error{"Operation and DB incompatible, or DB flags changed"} + BadReaderSlotError = &Error{"Invalid reuse of reader locktable slot"} + BadTransactionError = &Error{"Transaction cannot recover - it must be aborted"} + BadValueSizeError = &Error{"Too big key/data, key is empty, or wrong DUPFIXED size"} +) + +type Error struct { + message string +} + +func (e *Error) Error() { + return e.message +} @@ -0,0 +1,10 @@ +package bolt + +// info contains information about the database. +type info struct { + MapSize int + LastPageID int + LastTransactionID int + MaxReaders int + ReaderCount int +} @@ -0,0 +1,32 @@ +package bolt + +type meta struct { + magic int32 + version int32 + mapSize int + free *bucket + main *bucket + lastPageNumber int + transactionID int +} + +// TODO: #define mm_psize mm_dbs[0].md_pad +// TODO: #define mm_flags mm_dbs[0].md_flags + +// TODO: +// typedef union MDB_metabuf { +// MDB_page mb_page; +// struct { +// char mm_pad[PAGEHDRSZ]; +// MDB_meta mm_meta; +// } mb_metabuf; +// } MDB_metabuf; + +// TODO: +// typedef struct MDB_dbx { +// MDB_val md_name; /**< name of the database */ +// MDB_cmp_func *md_cmp; /**< function for comparing keys */ +// MDB_cmp_func *md_dcmp; /**< function for comparing data items */ +// MDB_rel_func *md_rel; /**< user relocate function */ +// void *md_relctx; /**< user-provided context for md_rel */ +// } MDB_dbx; @@ -0,0 +1,40 @@ +package bolt + +const ( + bigNode = 0x01 + subNode = 0x02 + dupNode = 0x04 +) + +type node struct { + lo int + hi int + flags int + keySize int + data []byte +} + +func (n *node) setFlags(f int) { + // Valid flags: (F_DUPDATA|F_SUBDATA|MDB_RESERVE|MDB_APPEND) + // TODO +} + +func (n *node) size() int { + return 0 // TODO: offsetof(MDB_node, mn_data) +} + +// TODO: #define INDXSIZE(k) (NODESIZE + ((k) == NULL ? 0 : (k)->mv_size)) +// TODO: #define LEAFSIZE(k, d) (NODESIZE + (k)->mv_size + (d)->mv_size) +// TODO: #define NODEPTR(p, i) ((MDB_node *)((char *)(p) + (p)->mp_ptrs[i])) +// TODO: #define NODEKEY(node) (void *)((node)->mn_data) +// TODO: #define NODEDATA(node) (void *)((char *)(node)->mn_data + (node)->mn_ksize) +// TODO: #define NODEPGNO(node) ((node)->mn_lo | ((pgno_t) (node)->mn_hi << 16) | (PGNO_TOPWORD ? ((pgno_t) (node)->mn_flags << PGNO_TOPWORD) : 0)) +// TODO: #define SETPGNO(node,pgno) do { (node)->mn_lo = (pgno) & 0xffff; (node)->mn_hi = (pgno) >> 16; if (PGNO_TOPWORD) (node)->mn_flags = (pgno) >> PGNO_TOPWORD; } while(0) +// TODO: #define NODEDSZ(node) ((node)->mn_lo | ((unsigned)(node)->mn_hi << 16)) +// TODO: #define SETDSZ(node,size) do { (node)->mn_lo = (size) & 0xffff; (node)->mn_hi = (size) >> 16;} while(0) +// TODO: #define NODEKSZ(node) ((node)->mn_ksize) + +// TODO: #define LEAF2KEY(p, i, ks) ((char *)(p) + PAGEHDRSZ + ((i)*(ks))) + +// TODO: #define MDB_GET_KEY(node, keyptr) { if ((keyptr) != NULL) { (keyptr)->mv_size = NODEKSZ(node); (keyptr)->mv_data = NODEKEY(node); } } +// TODO: #define MDB_GET_KEY2(node, key) { key.mv_size = NODEKSZ(node); key.mv_data = NODEKEY(node); } @@ -0,0 +1,44 @@ +package bolt + +import ( + "unsafe" +) + +const MinPageKeys = 2 +const FillThreshold = 250 // 25% + +const ( + BranchPage = 0x01 + LeafPage = 0x02 + OverflowPage = 0x04 + MetaPage = 0x08 + DirtyPage = 0x10 /**< dirty page, also set for #P_SUBP pages */ + SubPage = 0x40 + KeepPage = 0x8000 /**< leave this page alone during spill */ +) + +type page struct { + header struct { + id int + next *page // (?) + lower int + upper int + overflowPageCount int + } + metadata []byte +} + +// nodeCount returns the number of nodes on the page. +func (p *page) nodeCount() int { + return 0 // (p.header.lower - unsafe.Sizeof(p.header) >> 1 +} + +// remainingSize returns the number of bytes left in the page. +func (p *page) remainingSize() int { + return p.header.upper - p.header.lower +} + +// remainingSize returns the number of bytes left in the page. +func (p *page) remainingSize() int { + return p.header.upper - p.header.lower +} diff --git a/reader.go b/reader.go new file mode 100644 index 0000000..c51517c --- /dev/null +++ b/reader.go @@ -0,0 +1,5 @@ +package bolt + +type reader struct { + int transactionID +} @@ -0,0 +1,10 @@ +package bolt + +type Stat struct { + PageSize int + Depth int + BranchPageCount int + LeafPageCount int + OverflowPageCount int + EntryCount int +} diff --git a/transaction.go b/transaction.go new file mode 100644 index 0000000..74118d1 --- /dev/null +++ b/transaction.go @@ -0,0 +1,33 @@ +package bolt + +// TODO: #define DB_DIRTY 0x01 /**< DB was modified or is DUPSORT data */ +// TODO: #define DB_STALE 0x02 /**< Named-DB record is older than txnID */ +// TODO: #define DB_NEW 0x04 /**< Named-DB handle opened in this txn */ +// TODO: #define DB_VALID 0x08 /**< DB handle is valid, see also #MDB_VALID */ + +// TODO: #define MDB_TXN_RDONLY 0x01 /**< read-only transaction */ +// TODO: #define MDB_TXN_ERROR 0x02 /**< an error has occurred */ +// TODO: #define MDB_TXN_DIRTY 0x04 /**< must write, even if dirty list is empty */ +// TODO: #define MDB_TXN_SPILLS 0x08 /**< txn or a parent has spilled pages */ + +type Transaction interface { +} + +type transaction struct { + id int + flags int + db *db + parent *transaction + child *transaction + nextPageNumber int + freePages []int + spillPages []int + dirtyList []int + reader *reader + // TODO: bucketxs []*bucketx + buckets []*bucket + bucketFlags []int + cursors []*cursor + // Implicit from slices? TODO: MDB_dbi mt_numdbs; + mt_dirty_room int +} @@ -0,0 +1,14 @@ +package bolt + +import ( + "fmt" + "os" +) + +func warn(v ...interface{}) { + fmt.Fprintln(os.Stderr, v...) +} + +func warnf(msg string, v ...interface{}) { + fmt.Fprintf(os.Stderr, msg, v...) +} diff --git a/xcursor.go b/xcursor.go new file mode 100644 index 0000000..fa0e915 --- /dev/null +++ b/xcursor.go @@ -0,0 +1,8 @@ +package bolt + +type xcursor struct { + cursor cursor + bucket *bucket + bucketx *bucketx + bucketFlag int +} |