diff options
author | Ben Johnson <benbjohnson@yahoo.com> | 2014-02-21 17:14:56 -0700 |
---|---|---|
committer | Ben Johnson <benbjohnson@yahoo.com> | 2014-02-21 22:57:50 -0700 |
commit | 1ad2b99f281d587b767b36f886401e81d17915a9 (patch) | |
tree | 7b46bfc96689af14938a9f93aab732e3e46ee709 /bucket.go | |
parent | Merge pull request #49 from benbjohnson/stat (diff) | |
download | dedo-1ad2b99f281d587b767b36f886401e81d17915a9.tar.gz dedo-1ad2b99f281d587b767b36f886401e81d17915a9.tar.xz |
Refactor Transaction/Bucket API.
Diffstat (limited to 'bucket.go')
-rw-r--r-- | bucket.go | 105 |
1 files changed, 100 insertions, 5 deletions
@@ -1,9 +1,13 @@ package bolt +import ( + "bytes" +) + // Bucket represents a collection of key/value pairs inside the database. -// All keys inside the bucket are unique. The Bucket type is not typically used -// directly. Instead the bucket name is typically passed into the Get(), Put(), -// or Delete() functions. +// All keys inside the bucket are unique. +// +// Accessing or changing data from a Bucket whose Transaction has closed will cause a panic. type Bucket struct { *bucket name string @@ -21,8 +25,9 @@ func (b *Bucket) Name() string { return b.name } -// cursor creates a new cursor for this bucket. -func (b *Bucket) cursor() *Cursor { +// Cursor creates a new cursor for this bucket. +func (b *Bucket) Cursor() *Cursor { + _assert(b.transaction.isOpen(), "transaction not open") return &Cursor{ transaction: b.transaction, root: b.root, @@ -30,8 +35,98 @@ func (b *Bucket) cursor() *Cursor { } } +// Get retrieves the value for a key in a named bucket. +// Returns a nil value if the key does not exist. +func (b *Bucket) Get(key []byte) []byte { + _assert(b.transaction.isOpen(), "transaction not open") + 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 inside of the bucket. +// If the key exist then its previous value will be overwritten. +// Returns an error if 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 { + _assert(b.transaction.isOpen(), "transaction not open") + if !b.transaction.writable { + return ErrTransactionNotWritable + } else 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. + c.node(b.transaction).put(key, key, value, 0) + + 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 { + _assert(b.transaction.isOpen(), "transaction not open") + if !b.transaction.writable { + return ErrTransactionNotWritable + } + + // Move cursor to correct position. + c := b.Cursor() + c.Seek(key) + + // Delete the node if we have a matching key. + c.node(c.transaction).del(key) + + return nil +} + +// NextSequence returns an autoincrementing integer for the bucket. +// Returns an error if the bucket was created from a read-only transaction or +// if the next sequence will overflow the int type. +func (b *Bucket) NextSequence() (int, error) { + _assert(b.transaction.isOpen(), "transaction not open") + if !b.transaction.writable { + return 0, ErrTransactionNotWritable + } else 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. +func (b *Bucket) ForEach(fn func(k, v []byte) error) error { + _assert(b.transaction.isOpen(), "transaction not open") + 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 +} + // Stat returns stats on a bucket. func (b *Bucket) Stat() *BucketStat { + _assert(b.transaction.isOpen(), "transaction not open") s := &BucketStat{} b.transaction.forEachPage(b.root, 0, func(p *page, depth int) { if (p.flags & leafPageFlag) != 0 { |