aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO13
-rw-r--r--bucket.go22
-rw-r--r--bucket_test.go22
-rw-r--r--cursor.go20
-rw-r--r--db.go114
-rw-r--r--db_test.go22
-rw-r--r--doc.go17
-rw-r--r--example_test.go18
-rw-r--r--freelist.go12
-rw-r--r--freelist_test.go12
-rw-r--r--functional_test.go6
-rw-r--r--meta.go6
-rw-r--r--node.go40
-rw-r--r--rwtransaction.go50
-rw-r--r--rwtransaction_test.go40
-rw-r--r--transaction.go64
-rw-r--r--transaction_test.go54
17 files changed, 259 insertions, 273 deletions
diff --git a/TODO b/TODO
deleted file mode 100644
index 9c8a1a0..0000000
--- a/TODO
+++ /dev/null
@@ -1,13 +0,0 @@
-TODO
-====
-X Open DB.
-X Initialize transaction.
-- Cursor First, Get(key), Next
-- RWTransaction.insert()
- - rebalance
- - adjust cursors
-- RWTransaction Commmit
-
-
-
-
diff --git a/bucket.go b/bucket.go
index 6c1eb5c..e406a6e 100644
--- a/bucket.go
+++ b/bucket.go
@@ -7,9 +7,9 @@ import (
// Bucket represents a collection of key/value pairs inside the database.
type Bucket struct {
*bucket
- name string
- transaction *Transaction
- rwtransaction *RWTransaction
+ name string
+ tx *Tx
+ rwtx *RWTx
}
// bucket represents the on-file representation of a bucket.
@@ -25,17 +25,17 @@ func (b *Bucket) Name() string {
// Writable returns whether the bucket is writable.
func (b *Bucket) Writable() bool {
- return (b.rwtransaction != nil)
+ return (b.rwtx != nil)
}
// Cursor creates a cursor associated with the bucket.
-// The cursor is only valid as long as the Transaction is open.
+// The cursor is only valid as long as the transaction is open.
// Do not use a cursor after the transaction is closed.
func (b *Bucket) Cursor() *Cursor {
return &Cursor{
- transaction: b.transaction,
- root: b.root,
- stack: make([]elemRef, 0),
+ tx: b.tx,
+ root: b.root,
+ stack: make([]elemRef, 0),
}
}
@@ -74,7 +74,7 @@ func (b *Bucket) Put(key []byte, value []byte) error {
c.Seek(key)
// Insert the key/value.
- c.node(b.rwtransaction).put(key, key, value, 0)
+ c.node(b.rwtx).put(key, key, value, 0)
return nil
}
@@ -92,7 +92,7 @@ func (b *Bucket) Delete(key []byte) error {
c.Seek(key)
// Delete the node if we have a matching key.
- c.node(b.rwtransaction).del(key)
+ c.node(b.rwtx).del(key)
return nil
}
@@ -130,7 +130,7 @@ func (b *Bucket) ForEach(fn func(k, v []byte) error) error {
// Stat returns stats on a bucket.
func (b *Bucket) Stat() *BucketStat {
s := &BucketStat{}
- b.transaction.forEachPage(b.root, 0, func(p *page, depth int) {
+ b.tx.forEachPage(b.root, 0, func(p *page, depth int) {
if (p.flags & leafPageFlag) != 0 {
s.LeafPageCount++
s.KeyCount += int(p.count)
diff --git a/bucket_test.go b/bucket_test.go
index e4ccabd..a599557 100644
--- a/bucket_test.go
+++ b/bucket_test.go
@@ -27,7 +27,7 @@ func TestBucketGetNonExistent(t *testing.T) {
func TestBucketGetFromNode(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
- db.Do(func(txn *RWTransaction) error {
+ db.Do(func(txn *RWTx) error {
b := txn.Bucket("widgets")
b.Put([]byte("foo"), []byte("bar"))
value := b.Get([]byte("foo"))
@@ -54,7 +54,7 @@ func TestBucketPut(t *testing.T) {
func TestBucketPutReadOnly(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
- db.With(func(txn *Transaction) error {
+ db.With(func(txn *Tx) error {
b := txn.Bucket("widgets")
err := b.Put([]byte("foo"), []byte("bar"))
assert.Equal(t, err, ErrBucketNotWritable)
@@ -81,7 +81,7 @@ func TestBucketDelete(t *testing.T) {
func TestBucketDeleteReadOnly(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
- db.With(func(txn *Transaction) error {
+ db.With(func(txn *Tx) error {
b := txn.Bucket("widgets")
err := b.Delete([]byte("foo"))
assert.Equal(t, err, ErrBucketNotWritable)
@@ -120,7 +120,7 @@ func TestBucketNextSequence(t *testing.T) {
func TestBucketNextSequenceReadOnly(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
- db.With(func(txn *Transaction) error {
+ db.With(func(txn *Tx) error {
b := txn.Bucket("widgets")
i, err := b.NextSequence()
assert.Equal(t, i, 0)
@@ -134,7 +134,7 @@ func TestBucketNextSequenceReadOnly(t *testing.T) {
func TestBucketNextSequenceOverflow(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
- db.Do(func(txn *RWTransaction) error {
+ db.Do(func(txn *RWTx) error {
b := txn.Bucket("widgets")
b.bucket.sequence = uint64(maxInt)
seq, err := b.NextSequence()
@@ -218,7 +218,7 @@ func TestBucketPutKeyTooLarge(t *testing.T) {
// Ensure a bucket can calculate stats.
func TestBucketStat(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.Do(func(txn *RWTransaction) error {
+ db.Do(func(txn *RWTx) error {
// Add bucket with lots of keys.
txn.CreateBucket("widgets")
b := txn.Bucket("widgets")
@@ -241,7 +241,7 @@ func TestBucketStat(t *testing.T) {
return nil
})
- db.With(func(txn *Transaction) error {
+ db.With(func(txn *Tx) error {
b := txn.Bucket("widgets")
stat := b.Stat()
assert.Equal(t, stat.BranchPageCount, 15)
@@ -317,7 +317,7 @@ func TestBucketPutMultiple(t *testing.T) {
withOpenDB(func(db *DB, path string) {
// Bulk insert all values.
db.CreateBucket("widgets")
- rwtxn, _ := db.RWTransaction()
+ rwtxn, _ := db.RWTx()
b := rwtxn.Bucket("widgets")
for _, item := range items {
assert.NoError(t, b.Put(item.Key, item.Value))
@@ -325,7 +325,7 @@ func TestBucketPutMultiple(t *testing.T) {
assert.NoError(t, rwtxn.Commit())
// Verify all items exist.
- txn, _ := db.Transaction()
+ txn, _ := db.Tx()
b = txn.Bucket("widgets")
for _, item := range items {
value := b.Get(item.Key)
@@ -351,7 +351,7 @@ func TestBucketDeleteQuick(t *testing.T) {
withOpenDB(func(db *DB, path string) {
// Bulk insert all values.
db.CreateBucket("widgets")
- rwtxn, _ := db.RWTransaction()
+ rwtxn, _ := db.RWTx()
b := rwtxn.Bucket("widgets")
for _, item := range items {
assert.NoError(t, b.Put(item.Key, item.Value))
@@ -363,7 +363,7 @@ func TestBucketDeleteQuick(t *testing.T) {
assert.NoError(t, db.Delete("widgets", item.Key))
// Anything before our deletion index should be nil.
- txn, _ := db.Transaction()
+ txn, _ := db.Tx()
b := txn.Bucket("widgets")
for j, exp := range items {
if j > i {
diff --git a/cursor.go b/cursor.go
index f8e28ea..2907b84 100644
--- a/cursor.go
+++ b/cursor.go
@@ -6,18 +6,18 @@ import (
)
// Cursor represents an iterator that can traverse over all key/value pairs in a bucket in sorted order.
-// Cursors can be obtained from a Transaction and are valid as long as the Transaction is open.
+// Cursors can be obtained from a transaction and are valid as long as the transaction is open.
type Cursor struct {
- transaction *Transaction
- root pgid
- stack []elemRef
+ tx *Tx
+ root pgid
+ stack []elemRef
}
// First moves the cursor to the first item in the bucket and returns its key and value.
// If the bucket is empty then a nil key and value are returned.
func (c *Cursor) First() (key []byte, value []byte) {
c.stack = c.stack[:0]
- p, n := c.transaction.pageNode(c.root)
+ p, n := c.tx.pageNode(c.root)
c.stack = append(c.stack, elemRef{page: p, node: n, index: 0})
c.first()
return c.keyValue()
@@ -27,7 +27,7 @@ func (c *Cursor) First() (key []byte, value []byte) {
// If the bucket is empty then a nil key and value are returned.
func (c *Cursor) Last() (key []byte, value []byte) {
c.stack = c.stack[:0]
- p, n := c.transaction.pageNode(c.root)
+ p, n := c.tx.pageNode(c.root)
ref := elemRef{page: p, node: n}
ref.index = ref.count() - 1
c.stack = append(c.stack, ref)
@@ -116,7 +116,7 @@ func (c *Cursor) first() {
} else {
pgid = ref.page.branchPageElement(uint16(ref.index)).pgid
}
- p, n := c.transaction.pageNode(pgid)
+ p, n := c.tx.pageNode(pgid)
c.stack = append(c.stack, elemRef{page: p, node: n, index: 0})
}
}
@@ -137,7 +137,7 @@ func (c *Cursor) last() {
} else {
pgid = ref.page.branchPageElement(uint16(ref.index)).pgid
}
- p, n := c.transaction.pageNode(pgid)
+ p, n := c.tx.pageNode(pgid)
var nextRef = elemRef{page: p, node: n}
nextRef.index = nextRef.count() - 1
@@ -147,7 +147,7 @@ func (c *Cursor) last() {
// search recursively performs a binary search against a given page/node until it finds a given key.
func (c *Cursor) search(key []byte, pgid pgid) {
- p, n := c.transaction.pageNode(pgid)
+ p, n := c.tx.pageNode(pgid)
if p != nil {
_assert((p.flags&(branchPageFlag|leafPageFlag)) != 0, "invalid page type: "+p.typ())
}
@@ -251,7 +251,7 @@ func (c *Cursor) keyValue() ([]byte, []byte) {
}
// node returns the node that the cursor is currently positioned on.
-func (c *Cursor) node(t *RWTransaction) *node {
+func (c *Cursor) node(t *RWTx) *node {
_assert(len(c.stack) > 0, "accessing a node with a zero-length cursor stack")
// If the top of the stack is a leaf node then just return it.
diff --git a/db.go b/db.go
index 30b5c47..bf7be45 100644
--- a/db.go
+++ b/db.go
@@ -19,19 +19,19 @@ const maxMmapStep = 1 << 30 // 1GB
// All data access is performed through transactions which can be obtained through the DB.
// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called.
type DB struct {
- os _os
- syscall _syscall
- path string
- file file
- metafile file
- data []byte
- meta0 *meta
- meta1 *meta
- pageSize int
- opened bool
- rwtransaction *RWTransaction
- transactions []*Transaction
- freelist *freelist
+ os _os
+ syscall _syscall
+ path string
+ file file
+ metafile file
+ data []byte
+ meta0 *meta
+ meta1 *meta
+ pageSize int
+ opened bool
+ rwtx *RWTx
+ txs []*Tx
+ freelist *freelist
rwlock sync.Mutex // Allows only one writer at a time.
metalock sync.Mutex // Protects meta page access.
@@ -112,7 +112,7 @@ func (db *DB) Open(path string, mode os.FileMode) error {
}
// Read in the freelist.
- db.freelist = &freelist{pending: make(map[txnid][]pgid)}
+ db.freelist = &freelist{pending: make(map[txid][]pgid)}
db.freelist.read(db.page(db.meta().freelist))
// Mark the database as opened and return.
@@ -127,8 +127,8 @@ func (db *DB) mmap(minsz int) error {
defer db.mmaplock.Unlock()
// Dereference all mmap references before unmapping.
- if db.rwtransaction != nil {
- db.rwtransaction.dereference()
+ if db.rwtx != nil {
+ db.rwtx.dereference()
}
// Unmap existing data before continuing.
@@ -218,7 +218,7 @@ func (db *DB) init() error {
m.freelist = 2
m.buckets = 3
m.pgid = 4
- m.txnid = txnid(i)
+ m.txid = txid(i)
}
// Write an empty freelist at page 3.
@@ -259,11 +259,11 @@ func (db *DB) close() {
db.munmap()
}
-// Transaction creates a read-only transaction.
+// Tx creates a read-only transaction.
// Multiple read-only transactions can be used concurrently.
//
// IMPORTANT: You must close the transaction after you are finished or else the database will not reclaim old pages.
-func (db *DB) Transaction() (*Transaction, error) {
+func (db *DB) Tx() (*Tx, error) {
db.metalock.Lock()
defer db.metalock.Unlock()
@@ -278,23 +278,23 @@ func (db *DB) Transaction() (*Transaction, error) {
}
// Create a transaction associated with the database.
- t := &Transaction{}
+ t := &Tx{}
t.init(db)
// Keep track of transaction until it closes.
- db.transactions = append(db.transactions, t)
+ db.txs = append(db.txs, t)
return t, nil
}
-// RWTransaction creates a read/write transaction.
+// RWTx creates a read/write transaction.
// Only one read/write transaction is allowed at a time.
// You must call Commit() or Rollback() on the transaction to close it.
-func (db *DB) RWTransaction() (*RWTransaction, error) {
+func (db *DB) RWTx() (*RWTx, error) {
db.metalock.Lock()
defer db.metalock.Unlock()
- // Obtain writer lock. This is released by the RWTransaction when it closes.
+ // Obtain writer lock. This is released by the RWTx when it closes.
db.rwlock.Lock()
// Exit if the database is not open yet.
@@ -304,13 +304,13 @@ func (db *DB) RWTransaction() (*RWTransaction, error) {
}
// Create a transaction associated with the database.
- t := &RWTransaction{}
+ t := &RWTx{}
t.init(db)
- db.rwtransaction = t
+ db.rwtx = t
// Free any pages associated with closed read-only transactions.
- var minid txnid = 0xFFFFFFFFFFFFFFFF
- for _, t := range db.transactions {
+ var minid txid = 0xFFFFFFFFFFFFFFFF
+ for _, t := range db.txs {
if t.id() < minid {
minid = t.id()
}
@@ -322,8 +322,8 @@ func (db *DB) RWTransaction() (*RWTransaction, error) {
return t, nil
}
-// removeTransaction removes a transaction from the database.
-func (db *DB) removeTransaction(t *Transaction) {
+// removeTx removes a transaction from the database.
+func (db *DB) removeTx(t *Tx) {
db.metalock.Lock()
defer db.metalock.Unlock()
@@ -331,21 +331,21 @@ func (db *DB) removeTransaction(t *Transaction) {
db.mmaplock.RUnlock()
// Remove the transaction.
- for i, txn := range db.transactions {
+ for i, txn := range db.txs {
if txn == t {
- db.transactions = append(db.transactions[:i], db.transactions[i+1:]...)
+ db.txs = append(db.txs[:i], db.txs[i+1:]...)
break
}
}
}
-// Do executes a function within the context of a RWTransaction.
+// Do executes a function within the context of a RWTx.
// If no error is returned from the function then the transaction is committed.
// If an error is returned then the entire transaction is rolled back.
// Any error that is returned from the function or returned from the commit is
// returned from the Do() method.
-func (db *DB) Do(fn func(*RWTransaction) error) error {
- t, err := db.RWTransaction()
+func (db *DB) Do(fn func(*RWTx) error) error {
+ t, err := db.RWTx()
if err != nil {
return err
}
@@ -359,10 +359,10 @@ func (db *DB) Do(fn func(*RWTransaction) error) error {
return t.Commit()
}
-// With executes a function within the context of a Transaction.
+// With executes a function within the context of a transaction.
// Any error that is returned from the function is returned from the With() method.
-func (db *DB) With(fn func(*Transaction) error) error {
- t, err := db.Transaction()
+func (db *DB) With(fn func(*Tx) error) error {
+ t, err := db.Tx()
if err != nil {
return err
}
@@ -375,7 +375,7 @@ func (db *DB) With(fn func(*Transaction) error) error {
// ForEach executes a function for each key/value pair in a bucket.
// An error is returned if the bucket cannot be found.
func (db *DB) ForEach(name string, fn func(k, v []byte) error) error {
- return db.With(func(t *Transaction) error {
+ return db.With(func(t *Tx) error {
b := t.Bucket(name)
if b == nil {
return ErrBucketNotFound
@@ -387,7 +387,7 @@ func (db *DB) ForEach(name string, fn func(k, v []byte) error) error {
// Bucket retrieves a reference to a bucket.
// This is typically useful for checking the existence of a bucket.
func (db *DB) Bucket(name string) (*Bucket, error) {
- t, err := db.Transaction()
+ t, err := db.Tx()
if err != nil {
return nil, err
}
@@ -397,7 +397,7 @@ func (db *DB) Bucket(name string) (*Bucket, error) {
// Buckets retrieves a list of all buckets in the database.
func (db *DB) Buckets() ([]*Bucket, error) {
- t, err := db.Transaction()
+ t, err := db.Tx()
if err != nil {
return nil, err
}
@@ -409,7 +409,7 @@ func (db *DB) Buckets() ([]*Bucket, error) {
// This function can return an error if the bucket already exists, if the name
// is blank, or the bucket name is too long.
func (db *DB) CreateBucket(name string) error {
- return db.Do(func(t *RWTransaction) error {
+ return db.Do(func(t *RWTx) error {
return t.CreateBucket(name)
})
}
@@ -417,7 +417,7 @@ func (db *DB) CreateBucket(name string) error {
// CreateBucketIfNotExists creates a new bucket with the given name if it doesn't already exist.
// This function can return an error if the name is blank, or the bucket name is too long.
func (db *DB) CreateBucketIfNotExists(name string) error {
- return db.Do(func(t *RWTransaction) error {
+ return db.Do(func(t *RWTx) error {
return t.CreateBucketIfNotExists(name)
})
}
@@ -425,7 +425,7 @@ func (db *DB) CreateBucketIfNotExists(name string) error {
// DeleteBucket removes a bucket from the database.
// Returns an error if the bucket does not exist.
func (db *DB) DeleteBucket(name string) error {
- return db.Do(func(t *RWTransaction) error {
+ return db.Do(func(t *RWTx) error {
return t.DeleteBucket(name)
})
}
@@ -434,7 +434,7 @@ func (db *DB) DeleteBucket(name string) error {
// This function can return an error if the bucket does not exist.
func (db *DB) NextSequence(name string) (int, error) {
var seq int
- err := db.Do(func(t *RWTransaction) error {
+ err := db.Do(func(t *RWTx) error {
b := t.Bucket(name)
if b == nil {
return ErrBucketNotFound
@@ -453,7 +453,7 @@ func (db *DB) NextSequence(name string) (int, error) {
// Get retrieves the value for a key in a bucket.
// Returns an error if the key does not exist.
func (db *DB) Get(name string, key []byte) ([]byte, error) {
- t, err := db.Transaction()
+ t, err := db.Tx()
if err != nil {
return nil, err
}
@@ -482,7 +482,7 @@ func (db *DB) Get(name string, key []byte) ([]byte, error) {
// Put sets the value for a key in a bucket.
// Returns an error if the bucket is not found, if key is blank, if the key is too large, or if the value is too large.
func (db *DB) Put(name string, key []byte, value []byte) error {
- return db.Do(func(t *RWTransaction) error {
+ return db.Do(func(t *RWTx) error {
b := t.Bucket(name)
if b == nil {
return ErrBucketNotFound
@@ -494,7 +494,7 @@ func (db *DB) Put(name string, key []byte, value []byte) error {
// Delete removes a key from a bucket.
// Returns an error if the bucket cannot be found.
func (db *DB) Delete(name string, key []byte) error {
- return db.Do(func(t *RWTransaction) error {
+ return db.Do(func(t *RWTx) error {
b := t.Bucket(name)
if b == nil {
return ErrBucketNotFound
@@ -508,7 +508,7 @@ func (db *DB) Delete(name string, key []byte) error {
// using the database while a copy is in progress.
func (db *DB) Copy(w io.Writer) error {
// Maintain a reader transaction so pages don't get reclaimed.
- t, err := db.Transaction()
+ t, err := db.Tx()
if err != nil {
return err
}
@@ -549,15 +549,15 @@ func (db *DB) Stat() (*Stat, error) {
db.mmaplock.RLock()
var s = &Stat{
- MmapSize: len(db.data),
- TransactionCount: len(db.transactions),
+ MmapSize: len(db.data),
+ TxCount: len(db.txs),
}
// Release locks.
db.mmaplock.RUnlock()
db.metalock.Unlock()
- err := db.Do(func(t *RWTransaction) error {
+ err := db.Do(func(t *RWTx) error {
s.PageCount = int(t.meta.pgid)
s.FreePageCount = len(db.freelist.all())
s.PageSize = db.pageSize
@@ -582,7 +582,7 @@ func (db *DB) pageInBuffer(b []byte, id pgid) *page {
// meta retrieves the current meta page reference.
func (db *DB) meta() *meta {
- if db.meta0.txnid > db.meta1.txnid {
+ if db.meta0.txid > db.meta1.txid {
return db.meta0
}
return db.meta1
@@ -601,7 +601,7 @@ func (db *DB) allocate(count int) (*page, error) {
}
// Resize mmap() if we're at the end.
- p.id = db.rwtransaction.meta.pgid
+ p.id = db.rwtx.meta.pgid
var minsz = int((p.id+pgid(count))+1) * db.pageSize
if minsz >= len(db.data) {
if err := db.mmap(minsz); err != nil {
@@ -610,7 +610,7 @@ func (db *DB) allocate(count int) (*page, error) {
}
// Move the page id high water mark.
- db.rwtransaction.meta.pgid += pgid(count)
+ db.rwtx.meta.pgid += pgid(count)
return p, nil
}
@@ -634,6 +634,6 @@ type Stat struct {
// resize it.
MmapSize int
- // TransactionCount is the total number of reader transactions.
- TransactionCount int
+ // TxCount is the total number of reader transactions.
+ TxCount int
}
diff --git a/db_test.go b/db_test.go
index c8a8267..029d248 100644
--- a/db_test.go
+++ b/db_test.go
@@ -156,9 +156,9 @@ func TestDBCorruptMeta0(t *testing.T) {
}
// Ensure that a database cannot open a transaction when it's not open.
-func TestDBTransactionErrDatabaseNotOpen(t *testing.T) {
+func TestDBTxErrDatabaseNotOpen(t *testing.T) {
withDB(func(db *DB, path string) {
- txn, err := db.Transaction()
+ txn, err := db.Tx()
assert.Nil(t, txn)
assert.Equal(t, err, ErrDatabaseNotOpen)
})
@@ -173,9 +173,9 @@ func TestDBDeleteFromMissingBucket(t *testing.T) {
}
// Ensure a database can provide a transactional block.
-func TestDBTransactionBlock(t *testing.T) {
+func TestDBTxBlock(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- err := db.Do(func(txn *RWTransaction) error {
+ err := db.Do(func(txn *RWTx) error {
txn.CreateBucket("widgets")
b := txn.Bucket("widgets")
b.Put([]byte("foo"), []byte("bar"))
@@ -192,9 +192,9 @@ func TestDBTransactionBlock(t *testing.T) {
}
// Ensure a closed database returns an error while running a transaction block
-func TestDBTransactionBlockWhileClosed(t *testing.T) {
+func TestDBTxBlockWhileClosed(t *testing.T) {
withDB(func(db *DB, path string) {
- err := db.Do(func(txn *RWTransaction) error {
+ err := db.Do(func(txn *RWTx) error {
txn.CreateBucket("widgets")
return nil
})
@@ -276,7 +276,7 @@ func TestDBCopyFile(t *testing.T) {
// Ensure the database can return stats about itself.
func TestDBStat(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.Do(func(txn *RWTransaction) error {
+ db.Do(func(txn *RWTx) error {
txn.CreateBucket("widgets")
b := txn.Bucket("widgets")
for i := 0; i < 10000; i++ {
@@ -290,9 +290,9 @@ func TestDBStat(t *testing.T) {
db.Delete("widgets", []byte("1000"))
// Open some readers.
- t0, _ := db.Transaction()
- t1, _ := db.Transaction()
- t2, _ := db.Transaction()
+ t0, _ := db.Tx()
+ t1, _ := db.Tx()
+ t2, _ := db.Tx()
t2.Close()
// Obtain stats.
@@ -302,7 +302,7 @@ func TestDBStat(t *testing.T) {
assert.Equal(t, stat.FreePageCount, 2)
assert.Equal(t, stat.PageSize, 4096)
assert.Equal(t, stat.MmapSize, 4194304)
- assert.Equal(t, stat.TransactionCount, 2)
+ assert.Equal(t, stat.TxCount, 2)
// Close readers.
t0.Close()
diff --git a/doc.go b/doc.go
index d7f3ec1..ec576a2 100644
--- a/doc.go
+++ b/doc.go
@@ -2,7 +2,7 @@
Package bolt implements a low-level key/value store in pure Go. It supports
fully serializable transactions, ACID semantics, and lock-free MVCC with
multiple readers and a single writer. Bolt can be used for projects that
-want a simple data store without the need to add large dependencies such as
+want a simple data store without the need to add large dependencies such as
Postgres or MySQL.
Bolt is a single-level, zero-copy, B+tree data store. This means that Bolt is
@@ -14,15 +14,14 @@ The design of Bolt is based on Howard Chu's LMDB database project.
Basics
-There are only a few types in Bolt: DB, Bucket, Transaction, RWTransaction, and
-Cursor. The DB is a collection of buckets and is represented by a single file
-on disk. A bucket is a collection of unique keys that are associated with values.
+There are only a few types in Bolt: DB, Bucket, Tx, RWTx, and Cursor. The DB is
+a collection of buckets and is represented by a single file on disk. A bucket is
+a collection of unique keys that are associated with values.
-Transactions provide read-only access to data inside the database. They can
-retrieve key/value pairs and can use Cursors to iterate over the entire dataset.
-RWTransactions provide read-write access to the database. They can create and
-delete buckets and they can insert and remove keys. Only one RWTransaction is
-allowed at a time.
+Txs provide read-only access to data inside the database. They can retrieve
+key/value pairs and can use Cursors to iterate over the entire dataset. RWTxs
+provide read-write access to the database. They can create and delete buckets
+and they can insert and remove keys. Only one RWTx is allowed at a time.
Caveats
diff --git a/example_test.go b/example_test.go
index b4fac38..82db552 100644
--- a/example_test.go
+++ b/example_test.go
@@ -67,7 +67,7 @@ func ExampleDB_Do() {
defer db.Close()
// Execute several commands within a write transaction.
- err := db.Do(func(t *RWTransaction) error {
+ err := db.Do(func(t *RWTx) error {
if err := t.CreateBucket("widgets"); err != nil {
return err
}
@@ -100,7 +100,7 @@ func ExampleDB_With() {
db.Put("people", []byte("susy"), []byte("que"))
// Access data from within a read-only transactional block.
- db.With(func(t *Transaction) error {
+ db.With(func(t *Tx) error {
v := t.Bucket("people").Get([]byte("john"))
fmt.Printf("John's last name is %s.\n", string(v))
return nil
@@ -134,17 +134,17 @@ func ExampleDB_ForEach() {
// A liger is awesome.
}
-func ExampleRWTransaction() {
+func ExampleRWTx() {
// Open the database.
var db DB
- db.Open("/tmp/bolt/rwtransaction.db", 0666)
+ db.Open("/tmp/bolt/rwtx.db", 0666)
defer db.Close()
// Create a bucket.
db.CreateBucket("widgets")
// Create several keys in a transaction.
- rwtxn, _ := db.RWTransaction()
+ rwtxn, _ := db.RWTx()
b := rwtxn.Bucket("widgets")
b.Put([]byte("john"), []byte("blue"))
b.Put([]byte("abby"), []byte("red"))
@@ -152,7 +152,7 @@ func ExampleRWTransaction() {
rwtxn.Commit()
// Iterate over the values in sorted key order.
- txn, _ := db.Transaction()
+ txn, _ := db.Tx()
c := txn.Bucket("widgets").Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
fmt.Printf("%s likes %s\n", string(k), string(v))
@@ -165,10 +165,10 @@ func ExampleRWTransaction() {
// zephyr likes purple
}
-func ExampleRWTransaction_rollback() {
+func ExampleRWTx_rollback() {
// Open the database.
var db DB
- db.Open("/tmp/bolt/rwtransaction_rollback.db", 0666)
+ db.Open("/tmp/bolt/rwtx_rollback.db", 0666)
defer db.Close()
// Create a bucket.
@@ -178,7 +178,7 @@ func ExampleRWTransaction_rollback() {
db.Put("widgets", []byte("foo"), []byte("bar"))
// Update the key but rollback the transaction so it never saves.
- rwtxn, _ := db.RWTransaction()
+ rwtxn, _ := db.RWTx()
b := rwtxn.Bucket("widgets")
b.Put([]byte("foo"), []byte("baz"))
rwtxn.Rollback()
diff --git a/freelist.go b/freelist.go
index 3f5cf1c..636ed22 100644
--- a/freelist.go
+++ b/freelist.go
@@ -9,7 +9,7 @@ import (
// It also tracks pages that have been freed but are still in use by open transactions.
type freelist struct {
ids []pgid
- pending map[txnid][]pgid
+ pending map[txid][]pgid
}
// all returns a list of all free ids and all pending ids in one sorted list.
@@ -50,19 +50,19 @@ func (f *freelist) allocate(n int) pgid {
}
// free releases a page and its overflow for a given transaction id.
-func (f *freelist) free(txnid txnid, p *page) {
- var ids = f.pending[txnid]
+func (f *freelist) free(txid txid, p *page) {
+ var ids = f.pending[txid]
_assert(p.id > 1, "cannot free page 0 or 1: %d", p.id)
for i := 0; i < int(p.overflow+1); i++ {
ids = append(ids, p.id+pgid(i))
}
- f.pending[txnid] = ids
+ f.pending[txid] = ids
}
// release moves all page ids for a transaction id (or older) to the freelist.
-func (f *freelist) release(txnid txnid) {
+func (f *freelist) release(txid txid) {
for tid, ids := range f.pending {
- if tid <= txnid {
+ if tid <= txid {
f.ids = append(f.ids, ids...)
delete(f.pending, tid)
}
diff --git a/freelist_test.go b/freelist_test.go
index d452a2e..8421392 100644
--- a/freelist_test.go
+++ b/freelist_test.go
@@ -9,21 +9,21 @@ import (
// Ensure that a page is added to a transaction's freelist.
func TestFreelistFree(t *testing.T) {
- f := &freelist{pending: make(map[txnid][]pgid)}
+ f := &freelist{pending: make(map[txid][]pgid)}
f.free(100, &page{id: 12})
assert.Equal(t, f.pending[100], []pgid{12})
}
// Ensure that a page and its overflow is added to a transaction's freelist.
func TestFreelistFreeOverflow(t *testing.T) {
- f := &freelist{pending: make(map[txnid][]pgid)}
+ f := &freelist{pending: make(map[txid][]pgid)}
f.free(100, &page{id: 12, overflow: 3})
assert.Equal(t, f.pending[100], []pgid{12, 13, 14, 15})
}
// Ensure that a transaction's free pages can be released.
func TestFreelistRelease(t *testing.T) {
- f := &freelist{pending: make(map[txnid][]pgid)}
+ f := &freelist{pending: make(map[txid][]pgid)}
f.free(100, &page{id: 12, overflow: 1})
f.free(100, &page{id: 9})
f.free(102, &page{id: 39})
@@ -61,7 +61,7 @@ func TestFreelistRead(t *testing.T) {
ids[1] = 50
// Deserialize page into a freelist.
- f := &freelist{pending: make(map[txnid][]pgid)}
+ f := &freelist{pending: make(map[txid][]pgid)}
f.read(page)
// Ensure that there are two page ids in the freelist.
@@ -74,14 +74,14 @@ func TestFreelistRead(t *testing.T) {
func TestFreelistWrite(t *testing.T) {
// Create a freelist and write it to a page.
var buf [4096]byte
- f := &freelist{ids: []pgid{12, 39}, pending: make(map[txnid][]pgid)}
+ f := &freelist{ids: []pgid{12, 39}, pending: make(map[txid][]pgid)}
f.pending[100] = []pgid{28, 11}
f.pending[101] = []pgid{3}
p := (*page)(unsafe.Pointer(&buf[0]))
f.write(p)
// Read the page back out.
- f2 := &freelist{pending: make(map[txnid][]pgid)}
+ f2 := &freelist{pending: make(map[txid][]pgid)}
f2.read(p)
// Ensure that the freelist is correct.
diff --git a/functional_test.go b/functional_test.go
index 61f09bc..20af8fc 100644
--- a/functional_test.go
+++ b/functional_test.go
@@ -12,7 +12,7 @@ import (
)
// Ensure that multiple threads can use the DB without race detector errors.
-func TestParallelTransactions(t *testing.T) {
+func TestParallelTxs(t *testing.T) {
var mutex sync.RWMutex
err := quick.Check(func(numReaders, batchSize uint, items testdata) bool {
@@ -45,7 +45,7 @@ func TestParallelTransactions(t *testing.T) {
go func() {
mutex.RLock()
local := current
- txn, err := db.Transaction()
+ txn, err := db.Tx()
mutex.RUnlock()
if err == ErrDatabaseNotOpen {
wg.Done()
@@ -83,7 +83,7 @@ func TestParallelTransactions(t *testing.T) {
pending = pending[currentBatchSize:]
// Start write transaction.
- txn, err := db.RWTransaction()
+ txn, err := db.RWTx()
if !assert.NoError(t, err) {
t.FailNow()
}
diff --git a/meta.go b/meta.go
index 643d339..cee2d29 100644
--- a/meta.go
+++ b/meta.go
@@ -10,7 +10,7 @@ type meta struct {
buckets pgid
freelist pgid
pgid pgid
- txnid txnid
+ txid txid
}
// validate checks the marker bytes and version of the meta page to ensure it matches this binary.
@@ -31,13 +31,13 @@ func (m *meta) copy(dest *meta) {
dest.buckets = m.buckets
dest.freelist = m.freelist
dest.pgid = m.pgid
- dest.txnid = m.txnid
+ dest.txid = m.txid
}
// write writes the meta onto a page.
func (m *meta) write(p *page) {
// Page id is either going to be 0 or 1 which we can determine by the Txn ID.
- p.id = pgid(m.txnid % 2)
+ p.id = pgid(m.txid % 2)
p.flags |= metaPageFlag
m.copy(p.meta())
diff --git a/node.go b/node.go
index 68f651e..f0929c7 100644
--- a/node.go
+++ b/node.go
@@ -8,14 +8,14 @@ import (
// node represents an in-memory, deserialized page.
type node struct {
- transaction *RWTransaction
- isLeaf bool
- unbalanced bool
- key []byte
- depth int
- pgid pgid
- parent *node
- inodes inodes
+ tx *RWTx
+ isLeaf bool
+ unbalanced bool
+ key []byte
+ depth int
+ pgid pgid
+ parent *node
+ inodes inodes
}
// minKeys returns the minimum number of inodes this node should have.
@@ -56,7 +56,7 @@ func (n *node) root() *node {
// childAt returns the child node at a given index.
func (n *node) childAt(index int) *node {
_assert(!n.isLeaf, "invalid childAt(%d) on a leaf node", index)
- return n.transaction.node(n.inodes[index].pgid, n)
+ return n.tx.node(n.inodes[index].pgid, n)
}
// childIndex returns the index of a given child node.
@@ -214,7 +214,7 @@ func (n *node) split(pageSize int) []*node {
if len(current.inodes) >= minKeysPerPage && i < len(inodes)-minKeysPerPage && size+elemSize > threshold {
size = pageHeaderSize
nodes = append(nodes, current)
- current = &node{transaction: n.transaction, isLeaf: n.isLeaf}
+ current = &node{tx: n.tx, isLeaf: n.isLeaf}
}
size += elemSize
@@ -234,7 +234,7 @@ func (n *node) rebalance() {
n.unbalanced = false
// Ignore if node is above threshold (25%) and has enough keys.
- var threshold = n.transaction.db.pageSize / 4
+ var threshold = n.tx.db.pageSize / 4
if n.size() > threshold && len(n.inodes) > n.minKeys() {
return
}
@@ -244,20 +244,20 @@ func (n *node) rebalance() {
// If root node is a branch and only has one node then collapse it.
if !n.isLeaf && len(n.inodes) == 1 {
// Move child's children up.
- child := n.transaction.nodes[n.inodes[0].pgid]
+ child := n.tx.nodes[n.inodes[0].pgid]
n.isLeaf = child.isLeaf
n.inodes = child.inodes[:]
// Reparent all child nodes being moved.
for _, inode := range n.inodes {
- if child, ok := n.transaction.nodes[inode.pgid]; ok {
+ if child, ok := n.tx.nodes[inode.pgid]; ok {
child.parent = n
}
}
// Remove old child.
child.parent = nil
- delete(n.transaction.nodes, child.pgid)
+ delete(n.tx.nodes, child.pgid)
}
return
@@ -278,7 +278,7 @@ func (n *node) rebalance() {
if target.numChildren() > target.minKeys() {
if useNextSibling {
// Reparent and move node.
- if child, ok := n.transaction.nodes[target.inodes[0].pgid]; ok {
+ if child, ok := n.tx.nodes[target.inodes[0].pgid]; ok {
child.parent = n
}
n.inodes = append(n.inodes, target.inodes[0])
@@ -289,7 +289,7 @@ func (n *node) rebalance() {
target.key = target.inodes[0].key
} else {
// Reparent and move node.
- if child, ok := n.transaction.nodes[target.inodes[len(target.inodes)-1].pgid]; ok {
+ if child, ok := n.tx.nodes[target.inodes[len(target.inodes)-1].pgid]; ok {
child.parent = n
}
n.inodes = append(n.inodes, inode{})
@@ -309,7 +309,7 @@ func (n *node) rebalance() {
if useNextSibling {
// Reparent all child nodes being moved.
for _, inode := range target.inodes {
- if child, ok := n.transaction.nodes[inode.pgid]; ok {
+ if child, ok := n.tx.nodes[inode.pgid]; ok {
child.parent = n
}
}
@@ -317,11 +317,11 @@ func (n *node) rebalance() {
// Copy over inodes from target and remove target.
n.inodes = append(n.inodes, target.inodes...)
n.parent.del(target.key)
- delete(n.transaction.nodes, target.pgid)
+ delete(n.tx.nodes, target.pgid)
} else {
// Reparent all child nodes being moved.
for _, inode := range n.inodes {
- if child, ok := n.transaction.nodes[inode.pgid]; ok {
+ if child, ok := n.tx.nodes[inode.pgid]; ok {
child.parent = target
}
}
@@ -330,7 +330,7 @@ func (n *node) rebalance() {
target.inodes = append(target.inodes, n.inodes...)
n.parent.del(n.key)
n.parent.put(target.key, target.inodes[0].key, nil, target.pgid)
- delete(n.transaction.nodes, n.pgid)
+ delete(n.tx.nodes, n.pgid)
}
// Either this node or the target node was deleted from the parent so rebalance it.
diff --git a/rwtransaction.go b/rwtransaction.go
index 776cf55..0c670d9 100644
--- a/rwtransaction.go
+++ b/rwtransaction.go
@@ -5,29 +5,29 @@ import (
"unsafe"
)
-// RWTransaction represents a transaction that can read and write data.
+// RWTx represents a transaction that can read and write data.
// Only one read/write transaction can be active for a database at a time.
-// RWTransaction is composed of a read-only Transaction so it can also use
-// functions provided by Transaction.
-type RWTransaction struct {
- Transaction
+// RWTx is composed of a read-only transaction so it can also use
+// functions provided by Tx.
+type RWTx struct {
+ Tx
pending []*node
}
// init initializes the transaction.
-func (t *RWTransaction) init(db *DB) {
- t.Transaction.init(db)
- t.Transaction.rwtransaction = t
+func (t *RWTx) init(db *DB) {
+ t.Tx.init(db)
+ t.Tx.rwtx = t
t.pages = make(map[pgid]*page)
t.nodes = make(map[pgid]*node)
// Increment the transaction id.
- t.meta.txnid += txnid(1)
+ t.meta.txid += txid(1)
}
// CreateBucket creates a new bucket.
// Returns an error if the bucket already exists, if the bucket name is blank, or if the bucket name is too long.
-func (t *RWTransaction) CreateBucket(name string) error {
+func (t *RWTx) CreateBucket(name string) error {
// Check if bucket already exists.
if b := t.Bucket(name); b != nil {
return ErrBucketExists
@@ -52,7 +52,7 @@ func (t *RWTransaction) CreateBucket(name string) error {
// CreateBucketIfNotExists creates a new bucket if it doesn't already exist.
// Returns an error if the bucket name is blank, or if the bucket name is too long.
-func (t *RWTransaction) CreateBucketIfNotExists(name string) error {
+func (t *RWTx) CreateBucketIfNotExists(name string) error {
err := t.CreateBucket(name)
if err != nil && err != ErrBucketExists {
return err
@@ -62,7 +62,7 @@ func (t *RWTransaction) CreateBucketIfNotExists(name string) error {
// DeleteBucket deletes a bucket.
// Returns an error if the bucket cannot be found.
-func (t *RWTransaction) DeleteBucket(name string) error {
+func (t *RWTx) DeleteBucket(name string) error {
b := t.Bucket(name)
if b == nil {
return ErrBucketNotFound
@@ -81,7 +81,7 @@ func (t *RWTransaction) DeleteBucket(name string) error {
// Commit writes all changes to disk and updates the meta page.
// Returns an error if a disk write error occurs.
-func (t *RWTransaction) Commit() error {
+func (t *RWTx) Commit() error {
if t.db == nil {
return nil
}
@@ -118,11 +118,11 @@ func (t *RWTransaction) Commit() error {
}
// Rollback closes the transaction and ignores all previous updates.
-func (t *RWTransaction) Rollback() {
+func (t *RWTx) Rollback() {
t.close()
}
-func (t *RWTransaction) close() {
+func (t *RWTx) close() {
if t.db != nil {
t.db.rwlock.Unlock()
t.db = nil
@@ -130,7 +130,7 @@ func (t *RWTransaction) close() {
}
// allocate returns a contiguous block of memory starting at a given page.
-func (t *RWTransaction) allocate(count int) (*page, error) {
+func (t *RWTx) allocate(count int) (*page, error) {
p, err := t.db.allocate(count)
if err != nil {
return nil, err
@@ -143,14 +143,14 @@ func (t *RWTransaction) allocate(count int) (*page, error) {
}
// rebalance attempts to balance all nodes.
-func (t *RWTransaction) rebalance() {
+func (t *RWTx) rebalance() {
for _, n := range t.nodes {
n.rebalance()
}
}
// spill writes all the nodes to dirty pages.
-func (t *RWTransaction) spill() error {
+func (t *RWTx) spill() error {
// Keep track of the current root nodes.
// We will update this at the end once all nodes are created.
type root struct {
@@ -182,7 +182,7 @@ func (t *RWTransaction) spill() error {
// If this is a root node that split then create a parent node.
if n.parent == nil && len(newNodes) > 1 {
- n.parent = &node{transaction: t, isLeaf: false}
+ n.parent = &node{tx: t, isLeaf: false}
nodes = append(nodes, n.parent)
}
@@ -233,7 +233,7 @@ func (t *RWTransaction) spill() error {
}
// write writes any dirty pages to disk.
-func (t *RWTransaction) write() error {
+func (t *RWTx) write() error {
// Sort pages by id.
pages := make(pages, 0, len(t.pages))
for _, p := range t.pages {
@@ -258,7 +258,7 @@ func (t *RWTransaction) write() error {
}
// writeMeta writes the meta to the disk.
-func (t *RWTransaction) writeMeta() error {
+func (t *RWTx) writeMeta() error {
// Create a temporary buffer for the meta page.
buf := make([]byte, t.db.pageSize)
p := t.db.pageInBuffer(buf, 0)
@@ -271,14 +271,14 @@ func (t *RWTransaction) writeMeta() error {
}
// node creates a node from a page and associates it with a given parent.
-func (t *RWTransaction) node(pgid pgid, parent *node) *node {
+func (t *RWTx) node(pgid pgid, parent *node) *node {
// Retrieve node if it has already been fetched.
- if n := t.Transaction.node(pgid); n != nil {
+ if n := t.Tx.node(pgid); n != nil {
return n
}
// Otherwise create a branch and cache it.
- n := &node{transaction: t, parent: parent}
+ n := &node{tx: t, parent: parent}
if n.parent != nil {
n.depth = n.parent.depth + 1
}
@@ -289,7 +289,7 @@ func (t *RWTransaction) node(pgid pgid, parent *node) *node {
}
// dereference removes all references to the old mmap.
-func (t *RWTransaction) dereference() {
+func (t *RWTx) dereference() {
for _, n := range t.nodes {
n.dereference()
}
diff --git a/rwtransaction_test.go b/rwtransaction_test.go
index e45ec10..c94f534 100644
--- a/rwtransaction_test.go
+++ b/rwtransaction_test.go
@@ -9,31 +9,31 @@ import (
"github.com/stretchr/testify/assert"
)
-// Ensure that a RWTransaction can be retrieved.
-func TestRWTransaction(t *testing.T) {
+// Ensure that a RWTx can be retrieved.
+func TestRWTx(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- txn, err := db.RWTransaction()
+ txn, err := db.RWTx()
assert.NotNil(t, txn)
assert.NoError(t, err)
assert.Equal(t, txn.DB(), db)
})
}
-// Ensure that opening a RWTransaction while the DB is closed returns an error.
-func TestRWTransactionOpenWithClosedDB(t *testing.T) {
+// Ensure that opening a RWTx while the DB is closed returns an error.
+func TestRWTxOpenWithClosedDB(t *testing.T) {
withDB(func(db *DB, path string) {
- txn, err := db.RWTransaction()
+ txn, err := db.RWTx()
assert.Equal(t, err, ErrDatabaseNotOpen)
assert.Nil(t, txn)
})
}
// Ensure that retrieving all buckets returns writable buckets.
-func TestRWTransactionBuckets(t *testing.T) {
+func TestRWTxBuckets(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
db.CreateBucket("woojits")
- db.Do(func(txn *RWTransaction) error {
+ db.Do(func(txn *RWTx) error {
buckets := txn.Buckets()
assert.Equal(t, len(buckets), 2)
assert.Equal(t, buckets[0].Name(), "widgets")
@@ -50,7 +50,7 @@ func TestRWTransactionBuckets(t *testing.T) {
}
// Ensure that a bucket can be created and retrieved.
-func TestRWTransactionCreateBucket(t *testing.T) {
+func TestRWTxCreateBucket(t *testing.T) {
withOpenDB(func(db *DB, path string) {
// Create a bucket.
err := db.CreateBucket("widgets")
@@ -64,7 +64,7 @@ func TestRWTransactionCreateBucket(t *testing.T) {
}
// Ensure that a bucket can be created if it doesn't already exist.
-func TestRWTransactionCreateBucketIfNotExists(t *testing.T) {
+func TestRWTxCreateBucketIfNotExists(t *testing.T) {
withOpenDB(func(db *DB, path string) {
assert.NoError(t, db.CreateBucketIfNotExists("widgets"))
assert.NoError(t, db.CreateBucketIfNotExists("widgets"))
@@ -78,7 +78,7 @@ func TestRWTransactionCreateBucketIfNotExists(t *testing.T) {
}
// Ensure that a bucket cannot be created twice.
-func TestRWTransactionRecreateBucket(t *testing.T) {
+func TestRWTxRecreateBucket(t *testing.T) {
withOpenDB(func(db *DB, path string) {
// Create a bucket.
err := db.CreateBucket("widgets")
@@ -91,7 +91,7 @@ func TestRWTransactionRecreateBucket(t *testing.T) {
}
// Ensure that a bucket is created with a non-blank name.
-func TestRWTransactionCreateBucketWithoutName(t *testing.T) {
+func TestRWTxCreateBucketWithoutName(t *testing.T) {
withOpenDB(func(db *DB, path string) {
err := db.CreateBucket("")
assert.Equal(t, err, ErrBucketNameRequired)
@@ -99,7 +99,7 @@ func TestRWTransactionCreateBucketWithoutName(t *testing.T) {
}
// Ensure that a bucket name is not too long.
-func TestRWTransactionCreateBucketWithLongName(t *testing.T) {
+func TestRWTxCreateBucketWithLongName(t *testing.T) {
withOpenDB(func(db *DB, path string) {
err := db.CreateBucket(strings.Repeat("X", 255))
assert.NoError(t, err)
@@ -110,7 +110,7 @@ func TestRWTransactionCreateBucketWithLongName(t *testing.T) {
}
// Ensure that a bucket can be deleted.
-func TestRWTransactionDeleteBucket(t *testing.T) {
+func TestRWTxDeleteBucket(t *testing.T) {
withOpenDB(func(db *DB, path string) {
// Create a bucket and add a value.
db.CreateBucket("widgets")
@@ -136,7 +136,7 @@ func TestRWTransactionDeleteBucket(t *testing.T) {
}
// Ensure that an error is returned when deleting from a bucket that doesn't exist.
-func TestRWTransactionDeleteBucketNotFound(t *testing.T) {
+func TestRWTxDeleteBucketNotFound(t *testing.T) {
withOpenDB(func(db *DB, path string) {
err := db.DeleteBucket("widgets")
assert.Equal(t, err, ErrBucketNotFound)
@@ -144,19 +144,19 @@ func TestRWTransactionDeleteBucketNotFound(t *testing.T) {
}
// Benchmark the performance of bulk put transactions in random order.
-func BenchmarkRWTransactionPutRandom(b *testing.B) {
+func BenchmarkRWTxPutRandom(b *testing.B) {
indexes := rand.Perm(b.N)
value := []byte(strings.Repeat("0", 64))
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
- var txn *RWTransaction
+ var txn *RWTx
var bucket *Bucket
for i := 0; i < b.N; i++ {
if i%1000 == 0 {
if txn != nil {
txn.Commit()
}
- txn, _ = db.RWTransaction()
+ txn, _ = db.RWTx()
bucket = txn.Bucket("widgets")
}
bucket.Put([]byte(strconv.Itoa(indexes[i])), value)
@@ -166,11 +166,11 @@ func BenchmarkRWTransactionPutRandom(b *testing.B) {
}
// Benchmark the performance of bulk put transactions in sequential order.
-func BenchmarkRWTransactionPutSequential(b *testing.B) {
+func BenchmarkRWTxPutSequential(b *testing.B) {
value := []byte(strings.Repeat("0", 64))
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
- db.Do(func(txn *RWTransaction) error {
+ db.Do(func(txn *RWTx) error {
bucket := txn.Bucket("widgets")
for i := 0; i < b.N; i++ {
bucket.Put([]byte(strconv.Itoa(i)), value)
diff --git a/transaction.go b/transaction.go
index 857defb..91ab730 100644
--- a/transaction.go
+++ b/transaction.go
@@ -1,26 +1,26 @@
package bolt
-// Transaction represents a read-only transaction on the database.
+// Tx represents a read-only transaction on the database.
// It can be used for retrieving values for keys as well as creating cursors for
// iterating over the data.
//
// IMPORTANT: You must close transactions when you are done with them. Pages
// can not be reclaimed by the writer until no more transactions are using them.
// A long running read transaction can cause the database to quickly grow.
-type Transaction struct {
- db *DB
- rwtransaction *RWTransaction
- meta *meta
- buckets *buckets
- nodes map[pgid]*node
- pages map[pgid]*page
+type Tx struct {
+ db *DB
+ rwtx *RWTx
+ meta *meta
+ buckets *buckets
+ nodes map[pgid]*node
+ pages map[pgid]*page
}
-// txnid represents the internal transaction identifier.
-type txnid uint64
+// txid represents the internal transaction identifier.
+type txid uint64
// init initializes the transaction and associates it with a database.
-func (t *Transaction) init(db *DB) {
+func (t *Tx) init(db *DB) {
t.db = db
t.pages = nil
@@ -34,52 +34,52 @@ func (t *Transaction) init(db *DB) {
}
// id returns the transaction id.
-func (t *Transaction) id() txnid {
- return t.meta.txnid
+func (t *Tx) id() txid {
+ return t.meta.txid
}
// Close closes the transaction and releases any pages it is using.
-func (t *Transaction) Close() {
+func (t *Tx) Close() {
if t.db != nil {
- if t.rwtransaction != nil {
- t.rwtransaction.Rollback()
+ if t.rwtx != nil {
+ t.rwtx.Rollback()
} else {
- t.db.removeTransaction(t)
+ t.db.removeTx(t)
t.db = nil
}
}
}
// DB returns a reference to the database that created the transaction.
-func (t *Transaction) DB() *DB {
+func (t *Tx) DB() *DB {
return t.db
}
// Bucket retrieves a bucket by name.
// Returns nil if the bucket does not exist.
-func (t *Transaction) Bucket(name string) *Bucket {
+func (t *Tx) Bucket(name string) *Bucket {
b := t.buckets.get(name)
if b == nil {
return nil
}
return &Bucket{
- bucket: b,
- name: name,
- transaction: t,
- rwtransaction: t.rwtransaction,
+ bucket: b,
+ name: name,
+ tx: t,
+ rwtx: t.rwtx,
}
}
// Buckets retrieves a list of all buckets.
-func (t *Transaction) Buckets() []*Bucket {
+func (t *Tx) Buckets() []*Bucket {
buckets := make([]*Bucket, 0, len(t.buckets.items))
for name, b := range t.buckets.items {
bucket := &Bucket{
- bucket: b,
- name: name,
- transaction: t,
- rwtransaction: t.rwtransaction,
+ bucket: b,
+ name: name,
+ tx: t,
+ rwtx: t.rwtx,
}
buckets = append(buckets, bucket)
}
@@ -88,7 +88,7 @@ func (t *Transaction) Buckets() []*Bucket {
// page returns a reference to the page with a given id.
// If page has been written to then a temporary bufferred page is returned.
-func (t *Transaction) page(id pgid) *page {
+func (t *Tx) page(id pgid) *page {
// Check the dirty pages first.
if t.pages != nil {
if p, ok := t.pages[id]; ok {
@@ -101,7 +101,7 @@ func (t *Transaction) page(id pgid) *page {
}
// node returns a reference to the in-memory node for a given page, if it exists.
-func (t *Transaction) node(id pgid) *node {
+func (t *Tx) node(id pgid) *node {
if t.nodes == nil {
return nil
}
@@ -110,7 +110,7 @@ func (t *Transaction) node(id pgid) *node {
// pageNode returns the in-memory node, if it exists.
// Otherwise returns the underlying page.
-func (t *Transaction) pageNode(id pgid) (*page, *node) {
+func (t *Tx) pageNode(id pgid) (*page, *node) {
if n := t.node(id); n != nil {
return nil, n
}
@@ -118,7 +118,7 @@ func (t *Transaction) pageNode(id pgid) (*page, *node) {
}
// forEachPage iterates over every page within a given page and executes a function.
-func (t *Transaction) forEachPage(pgid pgid, depth int, fn func(*page, int)) {
+func (t *Tx) forEachPage(pgid pgid, depth int, fn func(*page, int)) {
p := t.page(pgid)
// Execute function.
diff --git a/transaction_test.go b/transaction_test.go
index 04cb44b..59f4dd5 100644
--- a/transaction_test.go
+++ b/transaction_test.go
@@ -14,7 +14,7 @@ import (
)
// Ensure that the database can retrieve a list of buckets.
-func TestTransactionBuckets(t *testing.T) {
+func TestTxBuckets(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("foo")
db.CreateBucket("bar")
@@ -28,8 +28,8 @@ func TestTransactionBuckets(t *testing.T) {
})
}
-// Ensure that a Transaction can retrieve a bucket.
-func TestTransactionBucketMissing(t *testing.T) {
+// Ensure that a Tx can retrieve a bucket.
+func TestTxBucketMissing(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
b, err := db.Bucket("widgets")
@@ -40,8 +40,8 @@ func TestTransactionBucketMissing(t *testing.T) {
})
}
-// Ensure that a Transaction retrieving a non-existent key returns nil.
-func TestTransactionGetMissing(t *testing.T) {
+// Ensure that a Tx retrieving a non-existent key returns nil.
+func TestTxGetMissing(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
db.Put("widgets", []byte("foo"), []byte("bar"))
@@ -51,11 +51,11 @@ func TestTransactionGetMissing(t *testing.T) {
})
}
-// Ensure that a Transaction cursor can iterate over an empty bucket without error.
-func TestTransactionCursorEmptyBucket(t *testing.T) {
+// Ensure that a Tx cursor can iterate over an empty bucket without error.
+func TestTxCursorEmptyBucket(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
- txn, _ := db.Transaction()
+ txn, _ := db.Tx()
c := txn.Bucket("widgets").Cursor()
k, v := c.First()
assert.Nil(t, k)
@@ -64,14 +64,14 @@ func TestTransactionCursorEmptyBucket(t *testing.T) {
})
}
-// Ensure that a Transaction cursor can iterate over a single root with a couple elements.
-func TestTransactionCursorLeafRoot(t *testing.T) {
+// Ensure that a Tx cursor can iterate over a single root with a couple elements.
+func TestTxCursorLeafRoot(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
db.Put("widgets", []byte("baz"), []byte{})
db.Put("widgets", []byte("foo"), []byte{0})
db.Put("widgets", []byte("bar"), []byte{1})
- txn, _ := db.Transaction()
+ txn, _ := db.Tx()
c := txn.Bucket("widgets").Cursor()
k, v := c.First()
@@ -98,14 +98,14 @@ func TestTransactionCursorLeafRoot(t *testing.T) {
})
}
-// Ensure that a Transaction cursor can iterate in reverse over a single root with a couple elements.
-func TestTransactionCursorLeafRootReverse(t *testing.T) {
+// Ensure that a Tx cursor can iterate in reverse over a single root with a couple elements.
+func TestTxCursorLeafRootReverse(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
db.Put("widgets", []byte("baz"), []byte{})
db.Put("widgets", []byte("foo"), []byte{0})
db.Put("widgets", []byte("bar"), []byte{1})
- txn, _ := db.Transaction()
+ txn, _ := db.Tx()
c := txn.Bucket("widgets").Cursor()
k, v := c.Last()
@@ -132,14 +132,14 @@ func TestTransactionCursorLeafRootReverse(t *testing.T) {
})
}
-// Ensure that a Transaction cursor can restart from the beginning.
-func TestTransactionCursorRestart(t *testing.T) {
+// Ensure that a Tx cursor can restart from the beginning.
+func TestTxCursorRestart(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.CreateBucket("widgets")
db.Put("widgets", []byte("bar"), []byte{})
db.Put("widgets", []byte("foo"), []byte{})
- txn, _ := db.Transaction()
+ txn, _ := db.Tx()
c := txn.Bucket("widgets").Cursor()
k, _ := c.First()
@@ -158,13 +158,13 @@ func TestTransactionCursorRestart(t *testing.T) {
})
}
-// Ensure that a transaction can iterate over all elements in a bucket.
-func TestTransactionCursorIterate(t *testing.T) {
+// Ensure that a Tx can iterate over all elements in a bucket.
+func TestTxCursorIterate(t *testing.T) {
f := func(items testdata) bool {
withOpenDB(func(db *DB, path string) {
// Bulk insert all values.
db.CreateBucket("widgets")
- rwtxn, _ := db.RWTransaction()
+ rwtxn, _ := db.RWTx()
b := rwtxn.Bucket("widgets")
for _, item := range items {
assert.NoError(t, b.Put(item.Key, item.Value))
@@ -176,7 +176,7 @@ func TestTransactionCursorIterate(t *testing.T) {
// Iterate over all items and check consistency.
var index = 0
- txn, _ := db.Transaction()
+ txn, _ := db.Tx()
c := txn.Bucket("widgets").Cursor()
for k, v := c.First(); k != nil && index < len(items); k, v = c.Next() {
assert.Equal(t, k, items[index].Key)
@@ -196,12 +196,12 @@ func TestTransactionCursorIterate(t *testing.T) {
}
// Ensure that a transaction can iterate over all elements in a bucket in reverse.
-func TestTransactionCursorIterateReverse(t *testing.T) {
+func TestTxCursorIterateReverse(t *testing.T) {
f := func(items testdata) bool {
withOpenDB(func(db *DB, path string) {
// Bulk insert all values.
db.CreateBucket("widgets")
- rwtxn, _ := db.RWTransaction()
+ rwtxn, _ := db.RWTx()
b := rwtxn.Bucket("widgets")
for _, item := range items {
assert.NoError(t, b.Put(item.Key, item.Value))
@@ -213,7 +213,7 @@ func TestTransactionCursorIterateReverse(t *testing.T) {
// Iterate over all items and check consistency.
var index = 0
- txn, _ := db.Transaction()
+ txn, _ := db.Tx()
c := txn.Bucket("widgets").Cursor()
for k, v := c.Last(); k != nil && index < len(items); k, v = c.Prev() {
assert.Equal(t, k, items[index].Key)
@@ -233,14 +233,14 @@ func TestTransactionCursorIterateReverse(t *testing.T) {
}
// Benchmark the performance iterating over a cursor.
-func BenchmarkTransactionCursor(b *testing.B) {
+func BenchmarkTxCursor(b *testing.B) {
indexes := rand.Perm(b.N)
value := []byte(strings.Repeat("0", 64))
withOpenDB(func(db *DB, path string) {
// Write data to bucket.
db.CreateBucket("widgets")
- db.Do(func(txn *RWTransaction) error {
+ db.Do(func(txn *RWTx) error {
bucket := txn.Bucket("widgets")
for i := 0; i < b.N; i++ {
bucket.Put([]byte(strconv.Itoa(indexes[i])), value)
@@ -250,7 +250,7 @@ func BenchmarkTransactionCursor(b *testing.B) {
b.ResetTimer()
// Iterate over bucket using cursor.
- db.With(func(txn *Transaction) error {
+ db.With(func(txn *Tx) error {
count := 0
c := txn.Bucket("widgets").Cursor()
for k, _ := c.First(); k != nil; k, _ = c.Next() {