bolt/bucket.go

164 lines
3.9 KiB
Go
Raw Normal View History

2014-01-08 15:06:17 +00:00
package bolt
2014-02-23 06:08:30 +00:00
import (
"bytes"
)
2014-02-12 21:57:27 +00:00
// Bucket represents a collection of key/value pairs inside the database.
2014-01-10 14:32:12 +00:00
type Bucket struct {
2014-01-14 20:01:02 +00:00
*bucket
name string
tx *Tx
2014-01-14 20:01:02 +00:00
}
2014-02-12 21:57:27 +00:00
// bucket represents the on-file representation of a bucket.
2014-01-14 20:01:02 +00:00
type bucket struct {
root pgid
2014-02-15 17:23:00 +00:00
sequence uint64
2014-01-08 15:06:17 +00:00
}
2014-01-26 22:29:06 +00:00
2014-01-30 05:11:46 +00:00
// Name returns the name of the bucket.
func (b *Bucket) Name() string {
return b.name
}
2014-02-23 06:08:30 +00:00
// Writable returns whether the bucket is writable.
func (b *Bucket) Writable() bool {
2014-03-09 03:25:37 +00:00
return b.tx.writable
2014-02-23 06:08:30 +00:00
}
// Cursor creates a cursor associated with the bucket.
// The cursor is only valid as long as the transaction is open.
2014-02-23 06:08:30 +00:00
// Do not use a cursor after the transaction is closed.
func (b *Bucket) Cursor() *Cursor {
2014-01-27 15:11:54 +00:00
return &Cursor{
tx: b.tx,
root: b.root,
stack: make([]elemRef, 0),
2014-01-26 22:29:06 +00:00
}
}
2014-02-21 16:20:45 +00:00
2014-02-23 06:08:30 +00:00
// Get retrieves the value for a key in the bucket.
// Returns a nil value if the key does not exist.
func (b *Bucket) Get(key []byte) []byte {
c := b.Cursor()
k, v := c.Seek(key)
// If our target node isn't the same key as what's passed in then return nil.
if !bytes.Equal(key, k) {
return nil
}
return v
}
// Put sets the value for a key in the bucket.
// If the key exist then its previous value will be overwritten.
// Returns an error if the bucket was created from a read-only transaction, if the key is blank, if the key is too large, or if the value is too large.
func (b *Bucket) Put(key []byte, value []byte) error {
if !b.Writable() {
return ErrBucketNotWritable
}
// Validate the key and data size.
if len(key) == 0 {
return ErrKeyRequired
} else if len(key) > MaxKeySize {
return ErrKeyTooLarge
} else if len(value) > MaxValueSize {
return ErrValueTooLarge
}
// Move cursor to correct position.
c := b.Cursor()
c.Seek(key)
// Insert the key/value.
2014-03-09 03:25:37 +00:00
c.node(b.tx).put(key, key, value, 0)
2014-02-23 06:08:30 +00:00
return nil
}
// Delete removes a key from the bucket.
// If the key does not exist then nothing is done and a nil error is returned.
// Returns an error if the bucket was created from a read-only transaction.
func (b *Bucket) Delete(key []byte) error {
if !b.Writable() {
return ErrBucketNotWritable
}
// Move cursor to correct position.
c := b.Cursor()
c.Seek(key)
// Delete the node if we have a matching key.
2014-03-09 03:25:37 +00:00
c.node(b.tx).del(key)
2014-02-23 06:08:30 +00:00
return nil
}
// NextSequence returns an autoincrementing integer for the bucket.
func (b *Bucket) NextSequence() (int, error) {
if !b.Writable() {
return 0, ErrBucketNotWritable
}
// Make sure next sequence number will not be larger than the maximum
// integer size of the system.
if b.bucket.sequence == uint64(maxInt) {
return 0, ErrSequenceOverflow
}
// Increment and return the sequence.
b.bucket.sequence++
return int(b.bucket.sequence), nil
}
// ForEach executes a function for each key/value pair in a bucket.
2014-03-15 15:14:20 +00:00
// If the provided function returns an error then the iteration is stopped and
// the error is returned to the caller.
2014-02-23 06:08:30 +00:00
func (b *Bucket) ForEach(fn func(k, v []byte) error) error {
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
if err := fn(k, v); err != nil {
return err
}
}
return nil
}
2014-02-21 16:20:45 +00:00
// Stat returns stats on a bucket.
func (b *Bucket) Stat() *BucketStat {
s := &BucketStat{}
b.tx.forEachPage(b.root, 0, func(p *page, depth int) {
2014-02-21 16:20:45 +00:00
if (p.flags & leafPageFlag) != 0 {
s.LeafPageCount++
s.KeyCount += int(p.count)
} else if (p.flags & branchPageFlag) != 0 {
s.BranchPageCount++
}
s.OverflowPageCount += int(p.overflow)
if depth+1 > s.MaxDepth {
s.MaxDepth = (depth + 1)
}
})
return s
}
// BucketStat represents stats on a bucket such as branch pages and leaf pages.
type BucketStat struct {
BranchPageCount int
LeafPageCount int
OverflowPageCount int
KeyCount int
MaxDepth int
}
type bucketsByName []*Bucket
func (s bucketsByName) Len() int { return len(s) }
func (s bucketsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s bucketsByName) Less(i, j int) bool { return s[i].name < s[j].name }