mirror of https://github.com/hak5/bolt.git
Begin Transaction.Cursor().
parent
f1d7fe5b08
commit
79d9b6bb5a
|
@ -1,5 +1,9 @@
|
|||
package bolt
|
||||
|
||||
const (
|
||||
MDB_DUPSORT = 0x04
|
||||
)
|
||||
|
||||
// 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)
|
||||
|
|
221
cursor.go
221
cursor.go
|
@ -2,15 +2,18 @@ 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 */
|
||||
const (
|
||||
c_initialized = 0x01 /**< cursor has been initialized and is valid */
|
||||
c_eof = 0x02 /**< No more data */
|
||||
c_sub = 0x04 /**< Cursor is a sub-cursor */
|
||||
c_del = 0x08 /**< last op was a cursor_del */
|
||||
c_splitting = 0x20 /**< Cursor is in page_split */
|
||||
c_untrack = 0x40 /**< Un-track cursor when closing */
|
||||
)
|
||||
|
||||
// TODO: #define MDB_NOSPILL 0x8000 /** Do not spill pages to disk if txn is getting full, may fail instead */
|
||||
|
||||
/*
|
||||
type Cursor interface {
|
||||
First() error
|
||||
FirstDup() error
|
||||
|
@ -28,37 +31,75 @@ type Cursor interface {
|
|||
Set() ([]byte, []byte, error)
|
||||
SetRange() ([]byte, []byte, error)
|
||||
}
|
||||
*/
|
||||
|
||||
type cursor struct {
|
||||
type Cursor struct {
|
||||
flags int
|
||||
_next *cursor
|
||||
backup *cursor
|
||||
xcursor *xcursor
|
||||
transaction *transaction
|
||||
next *Cursor
|
||||
backup *Cursor
|
||||
subcursor *Cursor
|
||||
transaction *Transaction
|
||||
bucketId int
|
||||
bucket *Bucket
|
||||
// bucketx *bucketx
|
||||
bucketFlag int
|
||||
snum int
|
||||
top int
|
||||
page []*page
|
||||
ki []int /**< stack of page indices */
|
||||
bucket *txnbucket
|
||||
subbucket *Bucket
|
||||
// subbucketx *bucketx
|
||||
subbucketFlag int
|
||||
snum int
|
||||
top int
|
||||
page []*page
|
||||
ki []int /**< stack of page indices */
|
||||
}
|
||||
|
||||
type xcursor struct {
|
||||
cursor cursor
|
||||
bucket *Bucket
|
||||
// bucketx *bucketx
|
||||
bucketFlag int
|
||||
// Initialize a cursor for a given transaction and database.
|
||||
func (c *Cursor) init(t *Transaction, b *txnbucket, sub *Cursor) {
|
||||
c.next = nil
|
||||
c.backup = nil
|
||||
c.transaction = t
|
||||
c.bucket = b
|
||||
c.snum = 0
|
||||
c.top = 0
|
||||
// TODO: mc->mc_pg[0] = 0;
|
||||
c.flags = 0
|
||||
|
||||
if (b.flags & MDB_DUPSORT) != 0 {
|
||||
sub.subcursor = nil
|
||||
sub.transaction = t
|
||||
sub.bucket = b
|
||||
sub.snum = 0
|
||||
sub.top = 0
|
||||
sub.flags = c_sub
|
||||
// TODO: mx->mx_dbx.md_name.mv_size = 0;
|
||||
// TODO: mx->mx_dbx.md_name.mv_data = NULL;
|
||||
c.subcursor = sub
|
||||
} else {
|
||||
c.subcursor = nil
|
||||
}
|
||||
|
||||
// Find the root page if the bucket is stale.
|
||||
if (c.bucket.flags & txnb_stale) != 0 {
|
||||
c.findPage(nil, ps_rootonly)
|
||||
}
|
||||
}
|
||||
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CONVERTED ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
|
||||
// Set or clear P_KEEP in dirty, non-overflow, non-sub pages watched by txn.
|
||||
// @param[in] mc A cursor handle for the current operation.
|
||||
// @param[in] pflags Flags of the pages to update:
|
||||
// P_DIRTY to set P_KEEP, P_DIRTY|P_KEEP to clear it.
|
||||
// @param[in] all No shortcuts. Needed except after a full #mdb_page_flush().
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (c *cursor) xkeep(pflags int, all int) error {
|
||||
func (c *Cursor) xkeep(pflags int, all int) error {
|
||||
/*
|
||||
enum { Mask = P_SUBP|P_DIRTY|P_KEEP };
|
||||
MDB_txn *txn = mc->mc_txn;
|
||||
|
@ -149,7 +190,7 @@ func (c *cursor) xkeep(pflags int, all int) error {
|
|||
// @param[in] key For a put operation, the key being stored.
|
||||
// @param[in] data For a put operation, the data being stored.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (c *cursor) spill(key []byte, data []byte) error {
|
||||
func (c *Cursor) spill(key []byte, data []byte) error {
|
||||
/*
|
||||
MDB_txn *txn = m0->mc_txn;
|
||||
MDB_page *dp;
|
||||
|
@ -424,7 +465,7 @@ func (p *page) copyTo(dst *page, size int) {
|
|||
// Touch a page: make it dirty and re-insert into tree with updated pgno.
|
||||
// @param[in] mc cursor pointing to the page to be touched
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (c *cursor) page_touch() int {
|
||||
func (c *Cursor) page_touch() int {
|
||||
/*
|
||||
MDB_page *mp = mc->mc_pg[mc->mc_top], *np;
|
||||
MDB_txn *txn = mc->mc_txn;
|
||||
|
@ -532,7 +573,7 @@ func (c *cursor) page_touch() int {
|
|||
// in *exactp (1 or 0).
|
||||
// Updates the cursor index with the index of the found entry.
|
||||
// If no entry larger or equal to the key is found, returns NULL.
|
||||
func (c *cursor) search(key []byte) (*node, bool) {
|
||||
func (c *Cursor) search(key []byte) (*node, bool) {
|
||||
/*
|
||||
unsigned int i = 0, nkeys;
|
||||
int low, high;
|
||||
|
@ -623,7 +664,7 @@ func (c *cursor) search(key []byte) (*node, bool) {
|
|||
return nil, false
|
||||
}
|
||||
|
||||
func (c *cursor) pop() {
|
||||
func (c *Cursor) pop() {
|
||||
/*
|
||||
if (mc->mc_snum) {
|
||||
#if MDB_DEBUG
|
||||
|
@ -640,7 +681,7 @@ func (c *cursor) pop() {
|
|||
}
|
||||
|
||||
/** Push a page onto the top of the cursor's stack. */
|
||||
func (c *cursor) push(p *page) error {
|
||||
func (c *Cursor) push(p *page) error {
|
||||
/*
|
||||
DPRINTF(("pushing page %"Z"u on db %d cursor %p", mp->mp_pgno,
|
||||
DDBI(mc), (void *) mc));
|
||||
|
@ -661,7 +702,7 @@ func (c *cursor) push(p *page) error {
|
|||
|
||||
// Finish #mdb_page_search() / #mdb_page_search_lowest().
|
||||
// The cursor is at the root page, set up the rest of it.
|
||||
func (c *cursor) searchRoot(key []byte, flags int) error {
|
||||
func (c *Cursor) searchRoot(key []byte, flags int) error {
|
||||
/*
|
||||
MDB_page *mp = mc->mc_pg[mc->mc_top];
|
||||
int rc;
|
||||
|
@ -733,7 +774,7 @@ func (c *cursor) searchRoot(key []byte, flags int) error {
|
|||
// before calling mdb_page_search_root(), because the callers
|
||||
// are all in situations where the current page is known to
|
||||
// be underfilled.
|
||||
func (c *cursor) searchLowest() error {
|
||||
func (c *Cursor) searchLowest() error {
|
||||
/*
|
||||
MDB_page *mp = mc->mc_pg[mc->mc_top];
|
||||
MDB_node *node = NODEPTR(mp, 0);
|
||||
|
@ -760,7 +801,7 @@ func (c *cursor) searchLowest() error {
|
|||
// This is used by #mdb_cursor_first() and #mdb_cursor_last().
|
||||
// If MDB_PS_ROOTONLY set, just fetch root node, no further lookups.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (c *cursor) findPage(key []byte, flags int) error {
|
||||
func (c *Cursor) findPage(key []byte, flags int) error {
|
||||
/*
|
||||
int rc;
|
||||
pgno_t root;
|
||||
|
@ -831,7 +872,7 @@ func (c *cursor) findPage(key []byte, flags int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *cursor) freeOverflowPage(p *page) error {
|
||||
func (c *Cursor) freeOverflowPage(p *page) error {
|
||||
/*
|
||||
MDB_txn *txn = mc->mc_txn;
|
||||
pgno_t pg = mp->mp_pgno;
|
||||
|
@ -913,7 +954,7 @@ func (c *cursor) freeOverflowPage(p *page) error {
|
|||
// @param[in] move_right Non-zero if the right sibling is requested,
|
||||
// otherwise the left sibling.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (c *cursor) sibling(moveRight bool) error {
|
||||
func (c *Cursor) sibling(moveRight bool) error {
|
||||
/*
|
||||
int rc;
|
||||
MDB_node *indx;
|
||||
|
@ -964,7 +1005,7 @@ func (c *cursor) sibling(moveRight bool) error {
|
|||
}
|
||||
|
||||
// Move the cursor to the next data item.
|
||||
func (c *cursor) next(key []byte, data []byte, op int) error {
|
||||
func (c *Cursor) Next(key []byte, data []byte, op int) error {
|
||||
/*
|
||||
MDB_page *mp;
|
||||
MDB_node *leaf;
|
||||
|
@ -1046,7 +1087,7 @@ func (c *cursor) next(key []byte, data []byte, op int) error {
|
|||
}
|
||||
|
||||
// Move the cursor to the previous data item.
|
||||
func (c *cursor) prev(key []byte, data []byte, op int) error {
|
||||
func (c *Cursor) prev(key []byte, data []byte, op int) error {
|
||||
/*
|
||||
MDB_page *mp;
|
||||
MDB_node *leaf;
|
||||
|
@ -1124,7 +1165,7 @@ func (c *cursor) prev(key []byte, data []byte, op int) error {
|
|||
|
||||
// Set the cursor on a specific data item.
|
||||
// (bool return is whether it is exact).
|
||||
func (c *cursor) set(key []byte, data []byte, op int) (error, bool) {
|
||||
func (c *Cursor) set(key []byte, data []byte, op int) (error, bool) {
|
||||
/*
|
||||
int rc;
|
||||
MDB_page *mp;
|
||||
|
@ -1310,7 +1351,7 @@ func (c *cursor) set(key []byte, data []byte, op int) (error, bool) {
|
|||
}
|
||||
|
||||
// Move the cursor to the first item in the database.
|
||||
func (c *cursor) first(key []byte, data []byte) error {
|
||||
func (c *Cursor) first(key []byte, data []byte) error {
|
||||
/*
|
||||
int rc;
|
||||
MDB_node *leaf;
|
||||
|
@ -1355,7 +1396,7 @@ func (c *cursor) first(key []byte, data []byte) error {
|
|||
}
|
||||
|
||||
// Move the cursor to the last item in the database.
|
||||
func (c *cursor) last() ([]byte, []byte) {
|
||||
func (c *Cursor) last() ([]byte, []byte) {
|
||||
/*
|
||||
int rc;
|
||||
MDB_node *leaf;
|
||||
|
@ -1401,7 +1442,7 @@ func (c *cursor) last() ([]byte, []byte) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *cursor) Get(key []byte, data []byte, op int) ([]byte, []byte, error) {
|
||||
func (c *Cursor) Get(key []byte, data []byte, op int) ([]byte, []byte, error) {
|
||||
/*
|
||||
int rc;
|
||||
int exact = 0;
|
||||
|
@ -1569,7 +1610,7 @@ func (c *cursor) Get(key []byte, data []byte, op int) ([]byte, []byte, error) {
|
|||
// Touch all the pages in the cursor stack. Set mc_top.
|
||||
// Makes sure all the pages are writable, before attempting a write operation.
|
||||
// @param[in] mc The cursor to operate on.
|
||||
func (c *cursor) touch() error {
|
||||
func (c *Cursor) touch() error {
|
||||
/*
|
||||
int rc = MDB_SUCCESS;
|
||||
|
||||
|
@ -2072,7 +2113,7 @@ func (c *cursor) touch() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *cursor) Del(flags int) error {
|
||||
func (c *Cursor) Del(flags int) error {
|
||||
/*
|
||||
MDB_node *leaf;
|
||||
MDB_page *mp;
|
||||
|
@ -2152,7 +2193,7 @@ func (c *cursor) Del(flags int) error {
|
|||
// unless allocating overflow pages for a large record.
|
||||
// @param[out] mp Address of a page, or NULL on failure.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (c *cursor) newPage(flags int, num int) ([]*page, error) {
|
||||
func (c *Cursor) newPage(flags int, num int) ([]*page, error) {
|
||||
/*
|
||||
MDB_page *np;
|
||||
int rc;
|
||||
|
@ -2194,7 +2235,7 @@ func (c *cursor) newPage(flags int, num int) ([]*page, error) {
|
|||
// should never happen since all callers already calculate the
|
||||
// page's free space before calling this function.
|
||||
// </ul>
|
||||
func (c *cursor) addNode(index int, key []byte, data []byte, pgno int, flags int) error {
|
||||
func (c *Cursor) addNode(index int, key []byte, data []byte, pgno int, flags int) error {
|
||||
/*
|
||||
unsigned int i;
|
||||
size_t node_size = NODESIZE;
|
||||
|
@ -2323,7 +2364,7 @@ func (c *cursor) addNode(index int, key []byte, data []byte, pgno int, flags int
|
|||
// @param[in] indx The index of the node to delete.
|
||||
// @param[in] ksize The size of a node. Only used if the page is
|
||||
// part of a #MDB_DUPFIXED database.
|
||||
func (c *cursor) deleteNode(ksize int) {
|
||||
func (c *Cursor) deleteNode(ksize int) {
|
||||
/*
|
||||
MDB_page *mp = mc->mc_pg[mc->mc_top];
|
||||
indx_t indx = mc->mc_ki[mc->mc_top];
|
||||
|
@ -2375,41 +2416,12 @@ func (c *cursor) deleteNode(ksize int) {
|
|||
*/
|
||||
}
|
||||
|
||||
// Initial setup of a sorted-dups cursor.
|
||||
// Sorted duplicates are implemented as a sub-database for the given key.
|
||||
// The duplicate data items are actually keys of the sub-database.
|
||||
// Operations on the duplicate data items are performed using a sub-cursor
|
||||
// initialized when the sub-database is first accessed. This function does
|
||||
// the preliminary setup of the sub-cursor, filling in the fields that
|
||||
// depend only on the parent DB.
|
||||
// @param[in] mc The main cursor whose sorted-dups cursor is to be initialized.
|
||||
func (c *cursor) xcursor_init0() {
|
||||
/*
|
||||
MDB_xcursor *mx = mc->mc_xcursor;
|
||||
|
||||
mx->mx_cursor.mc_xcursor = NULL;
|
||||
mx->mx_cursor.mc_txn = mc->mc_txn;
|
||||
mx->mx_cursor.mc_db = &mx->mx_db;
|
||||
mx->mx_cursor.mc_dbx = &mx->mx_dbx;
|
||||
mx->mx_cursor.mc_dbi = mc->mc_dbi;
|
||||
mx->mx_cursor.mc_dbflag = &mx->mx_dbflag;
|
||||
mx->mx_cursor.mc_snum = 0;
|
||||
mx->mx_cursor.mc_top = 0;
|
||||
mx->mx_cursor.mc_flags = C_SUB;
|
||||
mx->mx_dbx.md_name.mv_size = 0;
|
||||
mx->mx_dbx.md_name.mv_data = NULL;
|
||||
mx->mx_dbx.md_cmp = mc->mc_dbx->md_dcmp;
|
||||
mx->mx_dbx.md_dcmp = NULL;
|
||||
mx->mx_dbx.md_rel = mc->mc_dbx->md_rel;
|
||||
*/
|
||||
}
|
||||
|
||||
// Final setup of a sorted-dups cursor.
|
||||
// Sets up the fields that depend on the data from the main cursor.
|
||||
// @param[in] mc The main cursor whose sorted-dups cursor is to be initialized.
|
||||
// @param[in] node The data containing the #MDB_db record for the
|
||||
// sorted-dup database.
|
||||
func (c *cursor) xcursor_init1(n *node) {
|
||||
func (c *Cursor) xcursor_init1(n *node) {
|
||||
/*
|
||||
MDB_xcursor *mx = mc->mc_xcursor;
|
||||
|
||||
|
@ -2455,35 +2467,8 @@ func (c *cursor) xcursor_init1(n *node) {
|
|||
*/
|
||||
}
|
||||
|
||||
// Initialize a cursor for a given transaction and database.
|
||||
func (c *cursor) init(t *transaction, bucket *Bucket, mx *xcursor) {
|
||||
/*
|
||||
mc->mc_next = NULL;
|
||||
mc->mc_backup = NULL;
|
||||
mc->mc_dbi = dbi;
|
||||
mc->mc_txn = txn;
|
||||
mc->mc_db = &txn->mt_dbs[dbi];
|
||||
mc->mc_dbx = &txn->mt_dbxs[dbi];
|
||||
mc->mc_dbflag = &txn->mt_dbflags[dbi];
|
||||
mc->mc_snum = 0;
|
||||
mc->mc_top = 0;
|
||||
mc->mc_pg[0] = 0;
|
||||
mc->mc_flags = 0;
|
||||
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
|
||||
mdb_tassert(txn, mx != NULL);
|
||||
mc->mc_xcursor = mx;
|
||||
mdb_xcursor_init0(mc);
|
||||
} else {
|
||||
mc->mc_xcursor = NULL;
|
||||
}
|
||||
if (*mc->mc_dbflag & DB_STALE) {
|
||||
mdb_page_search(mc, NULL, MDB_PS_ROOTONLY);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Return the count of duplicate data items for the current key.
|
||||
func (c *cursor) count() (int, error) {
|
||||
func (c *Cursor) count() (int, error) {
|
||||
/*
|
||||
MDB_node *leaf;
|
||||
|
||||
|
@ -2507,7 +2492,7 @@ func (c *cursor) count() (int, error) {
|
|||
return 0, nil
|
||||
}
|
||||
|
||||
func (c *cursor) Close() {
|
||||
func (c *Cursor) Close() {
|
||||
/*
|
||||
if (mc && !mc->mc_backup) {
|
||||
// remove from txn, if tracked
|
||||
|
@ -2522,23 +2507,19 @@ func (c *cursor) Close() {
|
|||
*/
|
||||
}
|
||||
|
||||
func (c *cursor) Transaction() Transaction {
|
||||
/*
|
||||
if (!mc) return NULL;
|
||||
return mc->mc_txn;
|
||||
*/
|
||||
return nil
|
||||
func (c *Cursor) Transaction() *Transaction {
|
||||
return c.transaction
|
||||
}
|
||||
|
||||
func (c *cursor) Bucket() *Bucket {
|
||||
return c.bucket
|
||||
func (c *Cursor) Bucket() *Bucket {
|
||||
return c.bucket.bucket
|
||||
}
|
||||
|
||||
// Replace the key for a branch node with a new key.
|
||||
// @param[in] mc Cursor pointing to the node to operate on.
|
||||
// @param[in] key The new key to use.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (c *cursor) updateKey(key []byte) error {
|
||||
func (c *Cursor) updateKey(key []byte) error {
|
||||
/*
|
||||
MDB_page *mp;
|
||||
MDB_node *node;
|
||||
|
@ -2609,7 +2590,7 @@ func (c *cursor) updateKey(key []byte) error {
|
|||
}
|
||||
|
||||
// Move a node from csrc to cdst.
|
||||
func (c *cursor) moveNodeTo(dst *cursor) error {
|
||||
func (c *Cursor) moveNodeTo(dst *Cursor) error {
|
||||
/*
|
||||
MDB_node *srcnode;
|
||||
MDB_val key, data;
|
||||
|
@ -2786,7 +2767,7 @@ func (c *cursor) moveNodeTo(dst *cursor) error {
|
|||
// the \b csrc page will be freed.
|
||||
// @param[in] csrc Cursor pointing to the source page.
|
||||
// @param[in] cdst Cursor pointing to the destination page.
|
||||
func (c *cursor) mergePage(dst *cursor) error {
|
||||
func (c *Cursor) mergePage(dst *Cursor) error {
|
||||
/*
|
||||
int rc;
|
||||
indx_t i, j;
|
||||
|
@ -2901,7 +2882,7 @@ func (c *cursor) mergePage(dst *cursor) error {
|
|||
// Copy the contents of a cursor.
|
||||
// @param[in] csrc The cursor to copy from.
|
||||
// @param[out] cdst The cursor to copy to.
|
||||
func (c *cursor) copyTo(dst *cursor) {
|
||||
func (c *Cursor) copyTo(dst *Cursor) {
|
||||
/*
|
||||
unsigned int i;
|
||||
|
||||
|
@ -2924,7 +2905,7 @@ func (c *cursor) copyTo(dst *cursor) {
|
|||
// @param[in] mc Cursor pointing to the page where rebalancing
|
||||
// should begin.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (c *cursor) rebalance() error {
|
||||
func (c *Cursor) rebalance() error {
|
||||
/*
|
||||
MDB_node *node;
|
||||
int rc;
|
||||
|
@ -3079,7 +3060,7 @@ func (c *cursor) rebalance() error {
|
|||
}
|
||||
|
||||
// Complete a delete operation started by #mdb_cursor_del().
|
||||
func (c *cursor) del0(leaf *node) error {
|
||||
func (c *Cursor) del0(leaf *node) error {
|
||||
/*
|
||||
int rc;
|
||||
MDB_page *mp;
|
||||
|
@ -3149,7 +3130,7 @@ func (c *cursor) del0(leaf *node) error {
|
|||
// @param[in] newpgno The page number, if the new node is a branch node.
|
||||
// @param[in] nflags The #NODE_ADD_FLAGS for the new node.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (c *cursor) splitPage(newKey []byte, newData []byte, newpgno int, nflags int) error {
|
||||
func (c *Cursor) splitPage(newKey []byte, newData []byte, newpgno int, nflags int) error {
|
||||
/*
|
||||
unsigned int flags;
|
||||
int rc = MDB_SUCCESS, new_root = 0, did_split = 0;
|
||||
|
@ -3533,7 +3514,7 @@ func (c *cursor) splitPage(newKey []byte, newData []byte, newpgno int, nflags in
|
|||
// @param[in] mc Cursor on the DB to free.
|
||||
// @param[in] subs non-Zero to check for sub-DBs in this DB.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (c *cursor) drop0(subs int) error {
|
||||
func (c *Cursor) drop0(subs int) error {
|
||||
/*
|
||||
int rc;
|
||||
|
||||
|
|
143
db.go
143
db.go
|
@ -15,7 +15,9 @@ const (
|
|||
IntegerDupKey
|
||||
)
|
||||
|
||||
var DatabaseAlreadyOpenedError = &Error{"Database already open", nil}
|
||||
var DatabaseNotOpenError = &Error{"db is not open", nil}
|
||||
var DatabaseAlreadyOpenedError = &Error{"db already open", nil}
|
||||
var TransactionInProgressError = &Error{"writable transaction is already in progress", nil}
|
||||
|
||||
// TODO: #define MDB_FATAL_ERROR 0x80000000U /** Failed to update the meta page. Probably an I/O error. */
|
||||
// TODO: #define MDB_ENV_ACTIVE 0x20000000U /** Some fields are initialized. */
|
||||
|
@ -44,9 +46,9 @@ type DB struct {
|
|||
mmapSize int /**< size of the data memory map */
|
||||
size int /**< current file size */
|
||||
pbuf []byte
|
||||
transaction *transaction /**< current write transaction */
|
||||
transaction *Transaction /**< current write transaction */
|
||||
maxPageNumber int /**< me_mapsize / me_psize */
|
||||
pageState pageState /**< state of old pages from freeDB */
|
||||
pagestate pagestate /**< state of old pages from freeDB */
|
||||
dpages []*page /**< list of malloc'd blocks for re-use */
|
||||
freePages []int /** IDL of pages that became unused in a write txn */
|
||||
dirtyPages []int /** ID2L of pages written during a write txn. Length MDB_IDL_UM_SIZE. */
|
||||
|
@ -203,12 +205,50 @@ func (db *DB) close() {
|
|||
// TODO
|
||||
}
|
||||
|
||||
// Transaction creates a transaction that's associated with this database.
|
||||
func (db *DB) Transaction(writable bool) (*Transaction, error) {
|
||||
db.Lock()
|
||||
defer db.Unlock()
|
||||
|
||||
// Exit if the database is not open yet.
|
||||
if !db.opened {
|
||||
return nil, DatabaseNotOpenError
|
||||
}
|
||||
// Exit if a writable transaction is currently in progress.
|
||||
if writable && db.transaction != nil {
|
||||
return nil, TransactionInProgressError
|
||||
}
|
||||
|
||||
// Create a transaction associated with the database.
|
||||
t := &Transaction{
|
||||
db: db,
|
||||
writable: writable,
|
||||
}
|
||||
|
||||
// We only allow one writable transaction at a time so save the reference.
|
||||
if writable {
|
||||
db.transaction = t
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// page retrieves a page reference from a given byte array based on the current page size.
|
||||
func (db *DB) page(b []byte, id int) *page {
|
||||
return (*page)(unsafe.Pointer(&b[id*db.pageSize]))
|
||||
}
|
||||
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CONVERTED ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
|
||||
func (db *DB) freePage(p *page) {
|
||||
/*
|
||||
|
@ -266,103 +306,6 @@ func (db *DB) sync(force bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) Transaction(parent *transaction, flags int) (*transaction, error) {
|
||||
/*
|
||||
MDB_txn *txn;
|
||||
MDB_ntxn *ntxn;
|
||||
int rc, size, tsize = sizeof(MDB_txn);
|
||||
|
||||
if (env->me_flags & MDB_FATAL_ERROR) {
|
||||
DPUTS("environment had fatal error, must shutdown!");
|
||||
return MDB_PANIC;
|
||||
}
|
||||
if ((env->me_flags & MDB_RDONLY) && !(flags & MDB_RDONLY))
|
||||
return EACCES;
|
||||
if (parent) {
|
||||
// Nested transactions: Max 1 child, write txns only, no writemap
|
||||
if (parent->mt_child ||
|
||||
(flags & MDB_RDONLY) ||
|
||||
(parent->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR)) ||
|
||||
(env->me_flags & MDB_WRITEMAP))
|
||||
{
|
||||
return (parent->mt_flags & MDB_TXN_RDONLY) ? EINVAL : MDB_BAD_TXN;
|
||||
}
|
||||
tsize = sizeof(MDB_ntxn);
|
||||
}
|
||||
size = tsize + env->me_maxdbs * (sizeof(MDB_db)+1);
|
||||
if (!(flags & MDB_RDONLY))
|
||||
size += env->me_maxdbs * sizeof(MDB_cursor *);
|
||||
|
||||
if ((txn = calloc(1, size)) == NULL) {
|
||||
DPRINTF(("calloc: %s", strerror(ErrCode())));
|
||||
return ENOMEM;
|
||||
}
|
||||
txn->mt_dbs = (MDB_db *) ((char *)txn + tsize);
|
||||
if (flags & MDB_RDONLY) {
|
||||
txn->mt_flags |= MDB_TXN_RDONLY;
|
||||
txn->mt_dbflags = (unsigned char *)(txn->mt_dbs + env->me_maxdbs);
|
||||
} else {
|
||||
txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs);
|
||||
txn->mt_dbflags = (unsigned char *)(txn->mt_cursors + env->me_maxdbs);
|
||||
}
|
||||
txn->mt_env = env;
|
||||
|
||||
if (parent) {
|
||||
unsigned int i;
|
||||
txn->mt_u.dirty_list = malloc(sizeof(MDB_ID2)*MDB_IDL_UM_SIZE);
|
||||
if (!txn->mt_u.dirty_list ||
|
||||
!(txn->mt_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX)))
|
||||
{
|
||||
free(txn->mt_u.dirty_list);
|
||||
free(txn);
|
||||
return ENOMEM;
|
||||
}
|
||||
txn->mt_txnid = parent->mt_txnid;
|
||||
txn->mt_dirty_room = parent->mt_dirty_room;
|
||||
txn->mt_u.dirty_list[0].mid = 0;
|
||||
txn->mt_spill_pgs = NULL;
|
||||
txn->mt_next_pgno = parent->mt_next_pgno;
|
||||
parent->mt_child = txn;
|
||||
txn->mt_parent = parent;
|
||||
txn->mt_numdbs = parent->mt_numdbs;
|
||||
txn->mt_flags = parent->mt_flags;
|
||||
txn->mt_dbxs = parent->mt_dbxs;
|
||||
memcpy(txn->mt_dbs, parent->mt_dbs, txn->mt_numdbs * sizeof(MDB_db));
|
||||
// Copy parent's mt_dbflags, but clear DB_NEW
|
||||
for (i=0; i<txn->mt_numdbs; i++)
|
||||
txn->mt_dbflags[i] = parent->mt_dbflags[i] & ~DB_NEW;
|
||||
rc = 0;
|
||||
ntxn = (MDB_ntxn *)txn;
|
||||
ntxn->mnt_pgstate = env->me_pgstate; // save parent me_pghead & co
|
||||
if (env->me_pghead) {
|
||||
size = MDB_IDL_SIZEOF(env->me_pghead);
|
||||
env->me_pghead = mdb_midl_alloc(env->me_pghead[0]);
|
||||
if (env->me_pghead)
|
||||
memcpy(env->me_pghead, ntxn->mnt_pgstate.mf_pghead, size);
|
||||
else
|
||||
rc = ENOMEM;
|
||||
}
|
||||
if (!rc)
|
||||
rc = mdb_cursor_shadow(parent, txn);
|
||||
if (rc)
|
||||
mdb_txn_reset0(txn, "beginchild-fail");
|
||||
} else {
|
||||
rc = mdb_txn_renew0(txn);
|
||||
}
|
||||
if (rc)
|
||||
free(txn);
|
||||
else {
|
||||
*ret = txn;
|
||||
DPRINTF(("begin txn %"Z"u%c %p on mdbenv %p, root page %"Z"u",
|
||||
txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w',
|
||||
(void *) txn, (void *) env, txn->mt_dbs[MAIN_DBI].md_root));
|
||||
}
|
||||
|
||||
return rc;
|
||||
*/
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Check both meta pages to see which one is newer.
|
||||
// @param[in] env the environment handle
|
||||
// @return meta toggle (0 or 1).
|
||||
|
|
46
db_test.go
46
db_test.go
|
@ -180,6 +180,41 @@ func TestDBCorruptMeta1(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
// Transaction()
|
||||
//--------------------------------------
|
||||
|
||||
// Ensure that a database cannot open a transaction when it's not open.
|
||||
func TestDBTransactionDatabaseNotOpenError(t *testing.T) {
|
||||
withDB(func(db *DB, path string) {
|
||||
txn, err := db.Transaction(false)
|
||||
assert.Nil(t, txn)
|
||||
assert.Equal(t, err, DatabaseNotOpenError)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a database cannot open a writable transaction while one is in progress.
|
||||
func TestDBTransactionInProgressError(t *testing.T) {
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
db.Transaction(true)
|
||||
txn, err := db.Transaction(true)
|
||||
assert.Nil(t, txn)
|
||||
assert.Equal(t, err, TransactionInProgressError)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a database can create a new writable transaction.
|
||||
func TestDBTransactionWriter(t *testing.T) {
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
txn, err := db.Transaction(true)
|
||||
if assert.NotNil(t, txn) {
|
||||
assert.Equal(t, txn.db, db)
|
||||
assert.Equal(t, txn.writable, true)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
// withDB executes a function with a database reference.
|
||||
func withDB(fn func(*DB, string)) {
|
||||
f, _ := ioutil.TempFile("", "bolt-")
|
||||
|
@ -200,3 +235,14 @@ func withMockDB(fn func(*DB, *mockos, *mocksyscall, string)) {
|
|||
db.syscall = syscall
|
||||
fn(db, os, syscall, "/mock/db")
|
||||
}
|
||||
|
||||
// withOpenDB executes a function with an already opened database.
|
||||
func withOpenDB(fn func(*DB, string)) {
|
||||
withDB(func(db *DB, path string) {
|
||||
if err := db.Open(path, 0666); err != nil {
|
||||
panic("cannot open db: " + err.Error())
|
||||
}
|
||||
defer db.Close()
|
||||
fn(db, path)
|
||||
})
|
||||
}
|
||||
|
|
12
page.go
12
page.go
|
@ -38,10 +38,12 @@ const maxWriteByteCount uint = 0x80000000 // TODO: #define MAX_WRITE 0x80000000U
|
|||
// #define MDB_COMMIT_PAGES IOV_MAX
|
||||
// #endif
|
||||
|
||||
// TODO: #define MDB_PS_MODIFY 1
|
||||
// TODO: #define MDB_PS_ROOTONLY 2
|
||||
// TODO: #define MDB_PS_FIRST 4
|
||||
// TODO: #define MDB_PS_LAST 8
|
||||
const (
|
||||
MDB_PS_MODIFY = 1
|
||||
MDB_PS_ROOTONLY = 2
|
||||
MDB_PS_FIRST = 4
|
||||
MDB_PS_LAST = 8
|
||||
)
|
||||
|
||||
// TODO: #define MDB_SPLIT_REPLACE MDB_APPENDDUP /**< newkey is not new */
|
||||
|
||||
|
@ -58,7 +60,7 @@ type page struct {
|
|||
ptr int
|
||||
}
|
||||
|
||||
type pageState struct {
|
||||
type pagestate struct {
|
||||
head int /**< Reclaimed freeDB pages, or NULL before use */
|
||||
last int /**< ID of last used record, or 0 if !mf_pghead */
|
||||
}
|
||||
|
|
245
transaction.go
245
transaction.go
|
@ -1,44 +1,143 @@
|
|||
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 */
|
||||
var TransactionExistingChildError = &Error{"txn already has a child", nil}
|
||||
var TransactionReadOnlyChildError = &Error{"read-only txn cannot create a child", nil}
|
||||
|
||||
// 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 */
|
||||
const (
|
||||
txnb_dirty = 0x01 /**< DB was modified or is DUPSORT data */
|
||||
txnb_stale = 0x02 /**< Named-DB record is older than txnID */
|
||||
txnb_new = 0x04 /**< Named-DB handle opened in this txn */
|
||||
txnb_valid = 0x08 /**< DB handle is valid, see also #MDB_VALID */
|
||||
)
|
||||
|
||||
type Transaction interface {
|
||||
}
|
||||
const (
|
||||
ps_modify = 1
|
||||
ps_rootonly = 2
|
||||
ps_first = 4
|
||||
ps_last = 8
|
||||
)
|
||||
|
||||
type transaction struct {
|
||||
id int
|
||||
flags int
|
||||
db *DB
|
||||
parent *transaction
|
||||
child *transaction
|
||||
nextPageNumber int
|
||||
freePages []int
|
||||
spillPages []int
|
||||
dirtyList []int
|
||||
reader *reader
|
||||
type Transaction struct {
|
||||
id int
|
||||
db *DB
|
||||
writable bool
|
||||
dirty bool
|
||||
spilled bool
|
||||
err error
|
||||
parent *Transaction
|
||||
child *Transaction
|
||||
buckets []*txnbucket
|
||||
|
||||
pgno int
|
||||
freePages []pgno
|
||||
spillPages []pgno
|
||||
dirtyList []pgno
|
||||
reader *reader
|
||||
// TODO: bucketxs []*bucketx
|
||||
buckets []*Bucket
|
||||
bucketFlags []int
|
||||
cursors []*cursor
|
||||
// Implicit from slices? TODO: MDB_dbi mt_numdbs;
|
||||
mt_dirty_room int
|
||||
dirty_room int
|
||||
pagestate pagestate
|
||||
}
|
||||
|
||||
// ntxn represents a nested transaction.
|
||||
type ntxn struct {
|
||||
transaction *transaction /**< the transaction */
|
||||
pageState pageState /**< parent transaction's saved freestate */
|
||||
type txnbucket struct {
|
||||
bucket *Bucket
|
||||
cursor *Cursor
|
||||
flags int
|
||||
}
|
||||
|
||||
func (t *transaction) allocPage(num int) *page {
|
||||
// Transaction begins a nested child transaction. Child transactions are only
|
||||
// available to writable transactions and a transaction can only have one child
|
||||
// at a time.
|
||||
func (t *Transaction) Transaction() (*Transaction, error) {
|
||||
// Exit if parent already has a child transaction.
|
||||
if t.child != nil {
|
||||
return nil, TransactionExistingChildError
|
||||
}
|
||||
// Exit if using parent for read-only transaction.
|
||||
if !t.writable {
|
||||
return nil, TransactionReadOnlyChildError
|
||||
}
|
||||
// TODO: Exit if parent is in an error state.
|
||||
|
||||
// Create the child transaction and attach the parent.
|
||||
child := &Transaction{
|
||||
id: t.id,
|
||||
db: t.db,
|
||||
parent: t,
|
||||
writable: true,
|
||||
pgno: t.pgno,
|
||||
pagestate: t.db.pagestate,
|
||||
}
|
||||
copy(child.buckets, t.buckets)
|
||||
|
||||
// TODO: Remove DB_NEW flag.
|
||||
t.child = child
|
||||
|
||||
// TODO: wtf?
|
||||
// if (env->me_pghead) {
|
||||
// size = MDB_IDL_SIZEOF(env->me_pghead);
|
||||
// env->me_pghead = mdb_midl_alloc(env->me_pghead[0]);
|
||||
// if (env->me_pghead)
|
||||
// memcpy(env->me_pghead, ntxn->mnt_pgstate.mf_pghead, size);
|
||||
// else
|
||||
// rc = ENOMEM;
|
||||
// }
|
||||
|
||||
// TODO: Back up parent transaction's cursors.
|
||||
// if t.shadow(child); err != nil {
|
||||
// child.reset0()
|
||||
// return err
|
||||
// }
|
||||
|
||||
return child, nil
|
||||
}
|
||||
|
||||
func (t *Transaction) Cursor(b *Bucket) (*Cursor, error) {
|
||||
// TODO: if !(txn->mt_dbflags[dbi] & DB_VALID) return InvalidBucketError
|
||||
// TODO: if (txn->mt_flags & MDB_TXN_ERROR) return BadTransactionError
|
||||
|
||||
// Allow read access to the freelist
|
||||
// TODO: if (!dbi && !F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))
|
||||
|
||||
/*
|
||||
MDB_cursor *mc;
|
||||
size_t size = sizeof(MDB_cursor);
|
||||
|
||||
// Allow read access to the freelist
|
||||
if (!dbi && !F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))
|
||||
return EINVAL;
|
||||
|
||||
if ((mc = malloc(size)) != NULL) {
|
||||
mdb_cursor_init(mc, txn, dbi, (MDB_xcursor *)(mc + 1));
|
||||
if (txn->mt_cursors) {
|
||||
mc->mc_next = txn->mt_cursors[dbi];
|
||||
txn->mt_cursors[dbi] = mc;
|
||||
mc->mc_flags |= C_UNTRACK;
|
||||
}
|
||||
} else {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
*ret = mc;
|
||||
|
||||
return MDB_SUCCESS;
|
||||
*/
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CONVERTED ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
|
||||
func (t *Transaction) allocPage(num int) *page {
|
||||
/*
|
||||
MDB_env *env = txn->mt_env;
|
||||
MDB_page *ret = env->me_dpages;
|
||||
|
@ -74,7 +173,7 @@ func (t *transaction) allocPage(num int) *page {
|
|||
}
|
||||
|
||||
// Find oldest txnid still referenced. Expects txn->mt_txnid > 0.
|
||||
func (t *transaction) oldest() int {
|
||||
func (t *Transaction) oldest() int {
|
||||
/*
|
||||
int i;
|
||||
txnid_t mr, oldest = txn->mt_txnid - 1;
|
||||
|
@ -94,7 +193,7 @@ func (t *transaction) oldest() int {
|
|||
}
|
||||
|
||||
// Add a page to the txn's dirty list
|
||||
func (t *transaction) dirty(p *page) {
|
||||
func (t *Transaction) addDirtyPage(p *page) {
|
||||
/*
|
||||
MDB_ID2 mid;
|
||||
int rc, (*insert)(MDB_ID2L, MDB_ID2 *);
|
||||
|
@ -119,7 +218,7 @@ func (t *transaction) dirty(p *page) {
|
|||
// @param[in] mp the page being referenced. It must not be dirty.
|
||||
// @param[out] ret the writable page, if any. ret is unchanged if
|
||||
// mp wasn't spilled.
|
||||
func (t *transaction) unspill(p *page) *page {
|
||||
func (t *Transaction) unspill(p *page) *page {
|
||||
/*
|
||||
MDB_env *env = txn->mt_env;
|
||||
const MDB_txn *tx2;
|
||||
|
@ -173,7 +272,7 @@ func (t *transaction) unspill(p *page) *page {
|
|||
}
|
||||
|
||||
// Back up parent txn's cursors, then grab the originals for tracking
|
||||
func (t *transaction) shadow(dst *transaction) error {
|
||||
func (t *Transaction) shadow(dst *Transaction) error {
|
||||
/*
|
||||
MDB_cursor *mc, *bk;
|
||||
MDB_xcursor *mx;
|
||||
|
@ -214,7 +313,7 @@ func (t *transaction) shadow(dst *transaction) error {
|
|||
// @param[in] txn the transaction handle.
|
||||
// @param[in] merge true to keep changes to parent cursors, false to revert.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (t *transaction) closeCursors(merge bool) {
|
||||
func (t *Transaction) closeCursors(merge bool) {
|
||||
/*
|
||||
MDB_cursor **cursors = txn->mt_cursors, *mc, *next, *bk;
|
||||
MDB_xcursor *mx;
|
||||
|
@ -252,7 +351,7 @@ func (t *transaction) closeCursors(merge bool) {
|
|||
// Common code for #mdb_txn_begin() and #mdb_txn_renew().
|
||||
// @param[in] txn the transaction handle to initialize
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (t *transaction) renew() error {
|
||||
func (t *Transaction) renew() error {
|
||||
/*
|
||||
MDB_env *env = txn->mt_env;
|
||||
MDB_txninfo *ti = env->me_txns;
|
||||
|
@ -366,7 +465,7 @@ func (t *transaction) renew() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *transaction) Renew() error {
|
||||
func (t *Transaction) Renew() error {
|
||||
/*
|
||||
int rc;
|
||||
|
||||
|
@ -389,12 +488,12 @@ func (t *transaction) Renew() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *transaction) DB() *DB {
|
||||
func (t *Transaction) DB() *DB {
|
||||
return t.db
|
||||
}
|
||||
|
||||
// Export or close DBI handles opened in this txn.
|
||||
func (t *transaction) updateBuckets(keep bool) {
|
||||
func (t *Transaction) updateBuckets(keep bool) {
|
||||
/*
|
||||
int i;
|
||||
MDB_dbi n = txn->mt_numdbs;
|
||||
|
@ -423,7 +522,7 @@ func (t *transaction) updateBuckets(keep bool) {
|
|||
// May be called twice for readonly txns: First reset it, then abort.
|
||||
// @param[in] txn the transaction handle to reset
|
||||
// @param[in] act why the transaction is being reset
|
||||
func (t *transaction) reset(act string) {
|
||||
func (t *Transaction) reset(act string) {
|
||||
/*
|
||||
MDB_env *env = txn->mt_env;
|
||||
|
||||
|
@ -472,7 +571,7 @@ func (t *transaction) reset(act string) {
|
|||
*/
|
||||
}
|
||||
|
||||
func (t *transaction) Reset() {
|
||||
func (t *Transaction) Reset() {
|
||||
/*
|
||||
if (txn == NULL)
|
||||
return;
|
||||
|
@ -485,7 +584,7 @@ func (t *transaction) Reset() {
|
|||
*/
|
||||
}
|
||||
|
||||
func (t *transaction) Abort() {
|
||||
func (t *Transaction) Abort() {
|
||||
/*
|
||||
if (txn == NULL)
|
||||
return;
|
||||
|
@ -504,7 +603,7 @@ func (t *transaction) Abort() {
|
|||
|
||||
// Save the freelist as of this transaction to the freeDB.
|
||||
// This changes the freelist. Keep trying until it stabilizes.
|
||||
func (t *transaction) saveFreelist() error {
|
||||
func (t *Transaction) saveFreelist() error {
|
||||
/*
|
||||
// env->me_pghead[] can grow and shrink during this call.
|
||||
// env->me_pglast and txn->mt_free_pgs[] can only grow.
|
||||
|
@ -662,7 +761,7 @@ func (t *transaction) saveFreelist() error {
|
|||
// @param[in] txn the transaction that's being committed
|
||||
// @param[in] keep number of initial pages in dirty_list to keep dirty.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (t *transaction) flush(keep bool) error {
|
||||
func (t *Transaction) flush(keep bool) error {
|
||||
/*
|
||||
MDB_env *env = txn->mt_env;
|
||||
MDB_ID2L dl = txn->mt_u.dirty_list;
|
||||
|
@ -1005,7 +1104,7 @@ func (t *transaction) flush(keep bool) error {
|
|||
// Update the environment info to commit a transaction.
|
||||
// @param[in] txn the transaction that's being committed
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (t *transaction) writeMeta() error {
|
||||
func (t *Transaction) writeMeta() error {
|
||||
/*
|
||||
MDB_env *env;
|
||||
MDB_meta meta, metab, *mp;
|
||||
|
@ -1129,7 +1228,7 @@ func (t *transaction) writeMeta() error {
|
|||
// @param[out] ret address of a pointer where the page's address will be stored.
|
||||
// @param[out] lvl dirty_list inheritance level of found page. 1=current txn, 0=mapped page.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (t *transaction) getPage(id int) (*page, int, error) {
|
||||
func (t *Transaction) getPage(id int) (*page, int, error) {
|
||||
/*
|
||||
MDB_env *env = txn->mt_env;
|
||||
MDB_page *p = NULL;
|
||||
|
@ -1188,7 +1287,7 @@ func (t *transaction) getPage(id int) (*page, int, error) {
|
|||
// @param[in] leaf The node being read.
|
||||
// @param[out] data Updated to point to the node's data.
|
||||
// @return 0 on success, non-zero on failure.
|
||||
func (t *transaction) readNode(leaf *node, data []byte) error {
|
||||
func (t *Transaction) readNode(leaf *node, data []byte) error {
|
||||
/*
|
||||
MDB_page *omp; // overflow page
|
||||
pgno_t pgno;
|
||||
|
@ -1214,7 +1313,7 @@ func (t *transaction) readNode(leaf *node, data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *transaction) Get(bucket Bucket, key []byte) ([]byte, error) {
|
||||
func (t *Transaction) Get(bucket Bucket, key []byte) ([]byte, error) {
|
||||
/*
|
||||
MDB_cursor mc;
|
||||
MDB_xcursor mx;
|
||||
|
@ -1238,43 +1337,7 @@ func (t *transaction) Get(bucket Bucket, key []byte) ([]byte, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (t *transaction) Cursor(b Bucket) (Cursor, error) {
|
||||
/*
|
||||
MDB_cursor *mc;
|
||||
size_t size = sizeof(MDB_cursor);
|
||||
|
||||
if (txn == NULL || ret == NULL || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
|
||||
return EINVAL;
|
||||
|
||||
if (txn->mt_flags & MDB_TXN_ERROR)
|
||||
return MDB_BAD_TXN;
|
||||
|
||||
// Allow read access to the freelist
|
||||
if (!dbi && !F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))
|
||||
return EINVAL;
|
||||
|
||||
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT)
|
||||
size += sizeof(MDB_xcursor);
|
||||
|
||||
if ((mc = malloc(size)) != NULL) {
|
||||
mdb_cursor_init(mc, txn, dbi, (MDB_xcursor *)(mc + 1));
|
||||
if (txn->mt_cursors) {
|
||||
mc->mc_next = txn->mt_cursors[dbi];
|
||||
txn->mt_cursors[dbi] = mc;
|
||||
mc->mc_flags |= C_UNTRACK;
|
||||
}
|
||||
} else {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
*ret = mc;
|
||||
|
||||
return MDB_SUCCESS;
|
||||
*/
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (t *transaction) Renew1(c Cursor) error {
|
||||
func (t *Transaction) Renew1(c Cursor) error {
|
||||
/*
|
||||
if (txn == NULL || mc == NULL || mc->mc_dbi >= txn->mt_numdbs)
|
||||
return EINVAL;
|
||||
|
@ -1288,7 +1351,7 @@ func (t *transaction) Renew1(c Cursor) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *transaction) Delete(b *Bucket, key []byte, data []byte) error {
|
||||
func (t *Transaction) Delete(b *Bucket, key []byte, data []byte) error {
|
||||
/*
|
||||
MDB_cursor mc;
|
||||
MDB_xcursor mx;
|
||||
|
@ -1343,7 +1406,7 @@ func (t *transaction) Delete(b *Bucket, key []byte, data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *transaction) Put(b Bucket, key []byte, data []byte, flags int) error {
|
||||
func (t *Transaction) Put(b Bucket, key []byte, data []byte, flags int) error {
|
||||
/*
|
||||
MDB_cursor mc;
|
||||
MDB_xcursor mx;
|
||||
|
@ -1363,7 +1426,7 @@ func (t *transaction) Put(b Bucket, key []byte, data []byte, flags int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *transaction) Bucket(name string, flags int) (*Bucket, error) {
|
||||
func (t *Transaction) Bucket(name string, flags int) (*Bucket, error) {
|
||||
/*
|
||||
MDB_val key, data;
|
||||
MDB_dbi i;
|
||||
|
@ -1467,7 +1530,7 @@ func (t *transaction) Bucket(name string, flags int) (*Bucket, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (t *transaction) Stat(b Bucket) *stat {
|
||||
func (t *Transaction) Stat(b Bucket) *stat {
|
||||
/*
|
||||
if (txn == NULL || arg == NULL || dbi >= txn->mt_numdbs)
|
||||
return EINVAL;
|
||||
|
@ -1483,7 +1546,7 @@ func (t *transaction) Stat(b Bucket) *stat {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *transaction) BucketFlags(b Bucket) (int, error) {
|
||||
func (t *Transaction) BucketFlags(b Bucket) (int, error) {
|
||||
/*
|
||||
// We could return the flags for the FREE_DBI too but what's the point?
|
||||
if (txn == NULL || dbi < MAIN_DBI || dbi >= txn->mt_numdbs)
|
||||
|
@ -1494,7 +1557,7 @@ func (t *transaction) BucketFlags(b Bucket) (int, error) {
|
|||
return 0, nil
|
||||
}
|
||||
|
||||
func (t *transaction) Drop(b *Bucket, del int) error {
|
||||
func (t *Transaction) Drop(b *Bucket, del int) error {
|
||||
/*
|
||||
MDB_cursor *mc, *m2;
|
||||
int rc;
|
||||
|
|
Loading…
Reference in New Issue