Merge pull request #452 from jrick/restore_errors

Introduce errors package and restore API compatibility
pull/457/head
Marek Siarkowicz 2023-04-07 10:51:52 +02:00 committed by GitHub
commit a2395be6b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 219 additions and 96 deletions

View File

@ -11,7 +11,7 @@ import (
"golang.org/x/sys/unix"
"go.etcd.io/bbolt/internal/common"
"go.etcd.io/bbolt/errors"
)
// flock acquires an advisory lock on a file descriptor.
@ -38,7 +38,7 @@ func flock(db *DB, exclusive bool, timeout time.Duration) error {
// If we timed out then return an error.
if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
return common.ErrTimeout
return errors.ErrTimeout
}
// Wait for a bit and try again.

View File

@ -9,7 +9,7 @@ import (
"golang.org/x/sys/windows"
"go.etcd.io/bbolt/internal/common"
"go.etcd.io/bbolt/errors"
)
// fdatasync flushes written data to a file descriptor.
@ -44,7 +44,7 @@ func flock(db *DB, exclusive bool, timeout time.Duration) error {
// If we timed oumercit then return an error.
if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
return common.ErrTimeout
return errors.ErrTimeout
}
// Wait for a bit and try again.

View File

@ -5,6 +5,7 @@ import (
"fmt"
"unsafe"
"go.etcd.io/bbolt/errors"
"go.etcd.io/bbolt/internal/common"
)
@ -146,11 +147,11 @@ func (b *Bucket) openBucket(value []byte) *Bucket {
// The bucket instance is only valid for the lifetime of the transaction.
func (b *Bucket) CreateBucket(key []byte) (*Bucket, error) {
if b.tx.db == nil {
return nil, common.ErrTxClosed
return nil, errors.ErrTxClosed
} else if !b.tx.writable {
return nil, common.ErrTxNotWritable
return nil, errors.ErrTxNotWritable
} else if len(key) == 0 {
return nil, common.ErrBucketNameRequired
return nil, errors.ErrBucketNameRequired
}
// Move cursor to correct position.
@ -160,9 +161,9 @@ func (b *Bucket) CreateBucket(key []byte) (*Bucket, error) {
// Return an error if there is an existing key.
if bytes.Equal(key, k) {
if (flags & common.BucketLeafFlag) != 0 {
return nil, common.ErrBucketExists
return nil, errors.ErrBucketExists
}
return nil, common.ErrIncompatibleValue
return nil, errors.ErrIncompatibleValue
}
// Create empty, inline bucket.
@ -190,7 +191,7 @@ func (b *Bucket) CreateBucket(key []byte) (*Bucket, error) {
// The bucket instance is only valid for the lifetime of the transaction.
func (b *Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error) {
child, err := b.CreateBucket(key)
if err == common.ErrBucketExists {
if err == errors.ErrBucketExists {
return b.Bucket(key), nil
} else if err != nil {
return nil, err
@ -202,9 +203,9 @@ func (b *Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error) {
// Returns an error if the bucket does not exist, or if the key represents a non-bucket value.
func (b *Bucket) DeleteBucket(key []byte) error {
if b.tx.db == nil {
return common.ErrTxClosed
return errors.ErrTxClosed
} else if !b.Writable() {
return common.ErrTxNotWritable
return errors.ErrTxNotWritable
}
// Move cursor to correct position.
@ -213,9 +214,9 @@ func (b *Bucket) DeleteBucket(key []byte) error {
// Return an error if bucket doesn't exist or is not a bucket.
if !bytes.Equal(key, k) {
return common.ErrBucketNotFound
return errors.ErrBucketNotFound
} else if (flags & common.BucketLeafFlag) == 0 {
return common.ErrIncompatibleValue
return errors.ErrIncompatibleValue
}
// Recursively delete all child buckets.
@ -268,15 +269,15 @@ func (b *Bucket) Get(key []byte) []byte {
// 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.tx.db == nil {
return common.ErrTxClosed
return errors.ErrTxClosed
} else if !b.Writable() {
return common.ErrTxNotWritable
return errors.ErrTxNotWritable
} else if len(key) == 0 {
return common.ErrKeyRequired
return errors.ErrKeyRequired
} else if len(key) > MaxKeySize {
return common.ErrKeyTooLarge
return errors.ErrKeyTooLarge
} else if int64(len(value)) > MaxValueSize {
return common.ErrValueTooLarge
return errors.ErrValueTooLarge
}
// Move cursor to correct position.
@ -285,7 +286,7 @@ func (b *Bucket) Put(key []byte, value []byte) error {
// Return an error if there is an existing key with a bucket value.
if bytes.Equal(key, k) && (flags&common.BucketLeafFlag) != 0 {
return common.ErrIncompatibleValue
return errors.ErrIncompatibleValue
}
// Insert into node.
@ -300,9 +301,9 @@ func (b *Bucket) Put(key []byte, value []byte) error {
// Returns an error if the bucket was created from a read-only transaction.
func (b *Bucket) Delete(key []byte) error {
if b.tx.db == nil {
return common.ErrTxClosed
return errors.ErrTxClosed
} else if !b.Writable() {
return common.ErrTxNotWritable
return errors.ErrTxNotWritable
}
// Move cursor to correct position.
@ -316,7 +317,7 @@ func (b *Bucket) Delete(key []byte) error {
// Return an error if there is already existing bucket value.
if (flags & common.BucketLeafFlag) != 0 {
return common.ErrIncompatibleValue
return errors.ErrIncompatibleValue
}
// Delete the node if we have a matching key.
@ -333,9 +334,9 @@ func (b *Bucket) Sequence() uint64 {
// SetSequence updates the sequence number for the bucket.
func (b *Bucket) SetSequence(v uint64) error {
if b.tx.db == nil {
return common.ErrTxClosed
return errors.ErrTxClosed
} else if !b.Writable() {
return common.ErrTxNotWritable
return errors.ErrTxNotWritable
}
// Materialize the root node if it hasn't been already so that the
@ -352,9 +353,9 @@ func (b *Bucket) SetSequence(v uint64) error {
// NextSequence returns an autoincrementing integer for the bucket.
func (b *Bucket) NextSequence() (uint64, error) {
if b.tx.db == nil {
return 0, common.ErrTxClosed
return 0, errors.ErrTxClosed
} else if !b.Writable() {
return 0, common.ErrTxNotWritable
return 0, errors.ErrTxNotWritable
}
// Materialize the root node if it hasn't been already so that the
@ -375,7 +376,7 @@ func (b *Bucket) NextSequence() (uint64, error) {
// the bucket; this will result in undefined behavior.
func (b *Bucket) ForEach(fn func(k, v []byte) error) error {
if b.tx.db == nil {
return common.ErrTxClosed
return errors.ErrTxClosed
}
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
@ -388,7 +389,7 @@ func (b *Bucket) ForEach(fn func(k, v []byte) error) error {
func (b *Bucket) ForEachBucket(fn func(k []byte) error) error {
if b.tx.db == nil {
return common.ErrTxClosed
return errors.ErrTxClosed
}
c := b.Cursor()
for k, _, flags := c.first(); k != nil; k, _, flags = c.next() {

View File

@ -17,8 +17,8 @@ import (
"github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt"
berrors "go.etcd.io/bbolt/errors"
"go.etcd.io/bbolt/internal/btesting"
"go.etcd.io/bbolt/internal/common"
)
// Ensure that a bucket that gets a non-existent key returns nil.
@ -247,7 +247,7 @@ func TestBucket_Put_IncompatibleValue(t *testing.T) {
if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil {
t.Fatal(err)
}
if err := b0.Put([]byte("foo"), []byte("bar")); err != common.ErrIncompatibleValue {
if err := b0.Put([]byte("foo"), []byte("bar")); err != berrors.ErrIncompatibleValue {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -273,7 +273,7 @@ func TestBucket_Put_Closed(t *testing.T) {
t.Fatal(err)
}
if err := b.Put([]byte("foo"), []byte("bar")); err != common.ErrTxClosed {
if err := b.Put([]byte("foo"), []byte("bar")); err != berrors.ErrTxClosed {
t.Fatalf("unexpected error: %s", err)
}
}
@ -293,7 +293,7 @@ func TestBucket_Put_ReadOnly(t *testing.T) {
if err := db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("widgets"))
if err := b.Put([]byte("foo"), []byte("bar")); err != common.ErrTxNotWritable {
if err := b.Put([]byte("foo"), []byte("bar")); err != berrors.ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -561,7 +561,7 @@ func TestBucket_Delete_Bucket(t *testing.T) {
if _, err := b.CreateBucket([]byte("foo")); err != nil {
t.Fatal(err)
}
if err := b.Delete([]byte("foo")); err != common.ErrIncompatibleValue {
if err := b.Delete([]byte("foo")); err != berrors.ErrIncompatibleValue {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -584,7 +584,7 @@ func TestBucket_Delete_ReadOnly(t *testing.T) {
}
if err := db.View(func(tx *bolt.Tx) error {
if err := tx.Bucket([]byte("widgets")).Delete([]byte("foo")); err != common.ErrTxNotWritable {
if err := tx.Bucket([]byte("widgets")).Delete([]byte("foo")); err != berrors.ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -610,7 +610,7 @@ func TestBucket_Delete_Closed(t *testing.T) {
if err := tx.Rollback(); err != nil {
t.Fatal(err)
}
if err := b.Delete([]byte("foo")); err != common.ErrTxClosed {
if err := b.Delete([]byte("foo")); err != berrors.ErrTxClosed {
t.Fatalf("unexpected error: %s", err)
}
}
@ -781,7 +781,7 @@ func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) {
if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil {
t.Fatal(err)
}
if _, err := widgets.CreateBucket([]byte("foo")); err != common.ErrIncompatibleValue {
if _, err := widgets.CreateBucket([]byte("foo")); err != berrors.ErrIncompatibleValue {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -802,7 +802,7 @@ func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) {
if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil {
t.Fatal(err)
}
if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != common.ErrIncompatibleValue {
if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != berrors.ErrIncompatibleValue {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -944,7 +944,7 @@ func TestBucket_NextSequence_ReadOnly(t *testing.T) {
if err := db.View(func(tx *bolt.Tx) error {
_, err := tx.Bucket([]byte("widgets")).NextSequence()
if err != common.ErrTxNotWritable {
if err != berrors.ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -967,7 +967,7 @@ func TestBucket_NextSequence_Closed(t *testing.T) {
if err := tx.Rollback(); err != nil {
t.Fatal(err)
}
if _, err := b.NextSequence(); err != common.ErrTxClosed {
if _, err := b.NextSequence(); err != berrors.ErrTxClosed {
t.Fatal(err)
}
}
@ -1159,7 +1159,7 @@ func TestBucket_ForEach_Closed(t *testing.T) {
t.Fatal(err)
}
if err := b.ForEach(func(k, v []byte) error { return nil }); err != common.ErrTxClosed {
if err := b.ForEach(func(k, v []byte) error { return nil }); err != berrors.ErrTxClosed {
t.Fatalf("unexpected error: %s", err)
}
}
@ -1173,10 +1173,10 @@ func TestBucket_Put_EmptyKey(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err := b.Put([]byte(""), []byte("bar")); err != common.ErrKeyRequired {
if err := b.Put([]byte(""), []byte("bar")); err != berrors.ErrKeyRequired {
t.Fatalf("unexpected error: %s", err)
}
if err := b.Put(nil, []byte("bar")); err != common.ErrKeyRequired {
if err := b.Put(nil, []byte("bar")); err != berrors.ErrKeyRequired {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -1193,7 +1193,7 @@ func TestBucket_Put_KeyTooLarge(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err := b.Put(make([]byte, 32769), []byte("bar")); err != common.ErrKeyTooLarge {
if err := b.Put(make([]byte, 32769), []byte("bar")); err != berrors.ErrKeyTooLarge {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -1216,7 +1216,7 @@ func TestBucket_Put_ValueTooLarge(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err := b.Put([]byte("foo"), make([]byte, bolt.MaxValueSize+1)); err != common.ErrValueTooLarge {
if err := b.Put([]byte("foo"), make([]byte, bolt.MaxValueSize+1)); err != berrors.ErrValueTooLarge {
t.Fatalf("unexpected error: %s", err)
}
return nil

View File

@ -21,6 +21,7 @@ import (
"unicode/utf8"
bolt "go.etcd.io/bbolt"
berrors "go.etcd.io/bbolt/errors"
"go.etcd.io/bbolt/internal/common"
"go.etcd.io/bbolt/internal/guts_cli"
)
@ -941,12 +942,12 @@ func (cmd *keysCommand) Run(args ...string) error {
// Find bucket.
var lastbucket *bolt.Bucket = tx.Bucket([]byte(buckets[0]))
if lastbucket == nil {
return common.ErrBucketNotFound
return berrors.ErrBucketNotFound
}
for _, bucket := range buckets[1:] {
lastbucket = lastbucket.Bucket([]byte(bucket))
if lastbucket == nil {
return common.ErrBucketNotFound
return berrors.ErrBucketNotFound
}
}
@ -1017,7 +1018,7 @@ func (cmd *getCommand) Run(args ...string) error {
} else if len(buckets) == 0 {
return ErrBucketRequired
} else if len(key) == 0 {
return common.ErrKeyRequired
return berrors.ErrKeyRequired
}
// Open database.
@ -1032,12 +1033,12 @@ func (cmd *getCommand) Run(args ...string) error {
// Find bucket.
var lastbucket *bolt.Bucket = tx.Bucket([]byte(buckets[0]))
if lastbucket == nil {
return common.ErrBucketNotFound
return berrors.ErrBucketNotFound
}
for _, bucket := range buckets[1:] {
lastbucket = lastbucket.Bucket([]byte(bucket))
if lastbucket == nil {
return common.ErrBucketNotFound
return berrors.ErrBucketNotFound
}
}

View File

@ -5,6 +5,7 @@ import (
"fmt"
"sort"
"go.etcd.io/bbolt/errors"
"go.etcd.io/bbolt/internal/common"
)
@ -138,15 +139,15 @@ func (c *Cursor) Seek(seek []byte) (key []byte, value []byte) {
// Delete fails if current key/value is a bucket or if the transaction is not writable.
func (c *Cursor) Delete() error {
if c.bucket.tx.db == nil {
return common.ErrTxClosed
return errors.ErrTxClosed
} else if !c.bucket.Writable() {
return common.ErrTxNotWritable
return errors.ErrTxNotWritable
}
key, _, flags := c.keyValue()
// Return an error if current value is a bucket.
if (flags & common.BucketLeafFlag) != 0 {
return common.ErrIncompatibleValue
return errors.ErrIncompatibleValue
}
c.node().del(key)

View File

@ -12,8 +12,8 @@ import (
"testing/quick"
bolt "go.etcd.io/bbolt"
"go.etcd.io/bbolt/errors"
"go.etcd.io/bbolt/internal/btesting"
"go.etcd.io/bbolt/internal/common"
)
// Ensure that a cursor can return a reference to the bucket that created it.
@ -140,7 +140,7 @@ func TestCursor_Delete(t *testing.T) {
}
c.Seek([]byte("sub"))
if err := c.Delete(); err != common.ErrIncompatibleValue {
if err := c.Delete(); err != errors.ErrIncompatibleValue {
t.Fatalf("unexpected error: %s", err)
}

19
db.go
View File

@ -11,6 +11,7 @@ import (
"time"
"unsafe"
berrors "go.etcd.io/bbolt/errors"
"go.etcd.io/bbolt/internal/common"
)
@ -233,7 +234,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
db.pageSize = pgSize
} else {
_ = db.close()
return nil, common.ErrInvalid
return nil, berrors.ErrInvalid
}
}
@ -311,7 +312,7 @@ func (db *DB) getPageSize() (int, error) {
return db.pageSize, nil
}
return 0, common.ErrInvalid
return 0, berrors.ErrInvalid
}
// getPageSizeFromFirstMeta reads the pageSize from the first meta page
@ -324,7 +325,7 @@ func (db *DB) getPageSizeFromFirstMeta() (int, bool, error) {
return int(m.PageSize()), metaCanRead, nil
}
}
return 0, metaCanRead, common.ErrInvalid
return 0, metaCanRead, berrors.ErrInvalid
}
// getPageSizeFromSecondMeta reads the pageSize from the second meta page
@ -362,7 +363,7 @@ func (db *DB) getPageSizeFromSecondMeta() (int, bool, error) {
}
}
return 0, metaCanRead, common.ErrInvalid
return 0, metaCanRead, berrors.ErrInvalid
}
// loadFreelist reads the freelist if it is synced, or reconstructs it
@ -697,14 +698,14 @@ func (db *DB) beginTx() (*Tx, error) {
if !db.opened {
db.mmaplock.RUnlock()
db.metalock.Unlock()
return nil, common.ErrDatabaseNotOpen
return nil, berrors.ErrDatabaseNotOpen
}
// Exit if the database is not correctly mapped.
if db.data == nil {
db.mmaplock.RUnlock()
db.metalock.Unlock()
return nil, common.ErrInvalidMapping
return nil, berrors.ErrInvalidMapping
}
// Create a transaction associated with the database.
@ -730,7 +731,7 @@ func (db *DB) beginTx() (*Tx, error) {
func (db *DB) beginRWTx() (*Tx, error) {
// If the database was opened with Options.ReadOnly, return an error.
if db.readOnly {
return nil, common.ErrDatabaseReadOnly
return nil, berrors.ErrDatabaseReadOnly
}
// Obtain writer lock. This is released by the transaction when it closes.
@ -745,13 +746,13 @@ func (db *DB) beginRWTx() (*Tx, error) {
// Exit if the database is not open yet.
if !db.opened {
db.rwlock.Unlock()
return nil, common.ErrDatabaseNotOpen
return nil, berrors.ErrDatabaseNotOpen
}
// Exit if the database is not correctly mapped.
if db.data == nil {
db.rwlock.Unlock()
return nil, common.ErrInvalidMapping
return nil, berrors.ErrInvalidMapping
}
// Create a transaction associated with the database.

View File

@ -20,8 +20,8 @@ import (
"github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt"
berrors "go.etcd.io/bbolt/errors"
"go.etcd.io/bbolt/internal/btesting"
"go.etcd.io/bbolt/internal/common"
)
// pageSize is the size of one page in the data file.
@ -137,7 +137,7 @@ func TestOpen_ErrInvalid(t *testing.T) {
t.Fatal(err)
}
if _, err := bolt.Open(path, 0666, nil); err != common.ErrInvalid {
if _, err := bolt.Open(path, 0666, nil); err != berrors.ErrInvalid {
t.Fatalf("unexpected error: %s", err)
}
}
@ -173,7 +173,7 @@ func TestOpen_ErrVersionMismatch(t *testing.T) {
}
// Reopen data file.
if _, err := bolt.Open(path, 0666, nil); err != common.ErrVersionMismatch {
if _, err := bolt.Open(path, 0666, nil); err != berrors.ErrVersionMismatch {
t.Fatalf("unexpected error: %s", err)
}
}
@ -209,7 +209,7 @@ func TestOpen_ErrChecksum(t *testing.T) {
}
// Reopen data file.
if _, err := bolt.Open(path, 0666, nil); err != common.ErrChecksum {
if _, err := bolt.Open(path, 0666, nil); err != berrors.ErrChecksum {
t.Fatalf("unexpected error: %s", err)
}
}
@ -553,7 +553,7 @@ func TestDB_Open_ReadOnly(t *testing.T) {
}
// Can't launch read-write transaction.
if _, err := readOnlyDB.Begin(true); err != common.ErrDatabaseReadOnly {
if _, err := readOnlyDB.Begin(true); err != berrors.ErrDatabaseReadOnly {
t.Fatalf("unexpected error: %s", err)
}
@ -642,7 +642,7 @@ func TestOpen_RecoverFreeList(t *testing.T) {
// Ensure that a database cannot open a transaction when it's not open.
func TestDB_Begin_ErrDatabaseNotOpen(t *testing.T) {
var db bolt.DB
if _, err := db.Begin(false); err != common.ErrDatabaseNotOpen {
if _, err := db.Begin(false); err != berrors.ErrDatabaseNotOpen {
t.Fatalf("unexpected error: %s", err)
}
}
@ -728,7 +728,7 @@ func TestDB_Concurrent_WriteTo(t *testing.T) {
// Ensure that opening a transaction while the DB is closed returns an error.
func TestDB_BeginRW_Closed(t *testing.T) {
var db bolt.DB
if _, err := db.Begin(true); err != common.ErrDatabaseNotOpen {
if _, err := db.Begin(true); err != berrors.ErrDatabaseNotOpen {
t.Fatalf("unexpected error: %s", err)
}
}
@ -832,7 +832,7 @@ func TestDB_Update_Closed(t *testing.T) {
t.Fatal(err)
}
return nil
}); err != common.ErrDatabaseNotOpen {
}); err != berrors.ErrDatabaseNotOpen {
t.Fatalf("unexpected error: %s", err)
}
}

View File

@ -7,7 +7,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.etcd.io/bbolt/internal/common"
"go.etcd.io/bbolt/errors"
)
func TestOpenWithPreLoadFreelist(t *testing.T) {
@ -78,7 +78,7 @@ func TestMethodPage(t *testing.T) {
name: "readonly mode without preloading free pages",
readonly: true,
preLoadFreePage: false,
expectedError: common.ErrFreePagesNotLoaded,
expectedError: errors.ErrFreePagesNotLoaded,
},
}

114
errors.go Normal file
View File

@ -0,0 +1,114 @@
package bbolt
import "go.etcd.io/bbolt/errors"
// These errors can be returned when opening or calling methods on a DB.
var (
// ErrDatabaseNotOpen is returned when a DB instance is accessed before it
// is opened or after it is closed.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrDatabaseNotOpen = errors.ErrDatabaseNotOpen
// ErrDatabaseOpen is returned when opening a database that is
// already open.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrDatabaseOpen = errors.ErrDatabaseOpen
// ErrInvalid is returned when both meta pages on a database are invalid.
// This typically occurs when a file is not a bolt database.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrInvalid = errors.ErrInvalid
// ErrInvalidMapping is returned when the database file fails to get mapped.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrInvalidMapping = errors.ErrInvalidMapping
// ErrVersionMismatch is returned when the data file was created with a
// different version of Bolt.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrVersionMismatch = errors.ErrVersionMismatch
// ErrChecksum is returned when either meta page checksum does not match.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrChecksum = errors.ErrChecksum
// ErrTimeout is returned when a database cannot obtain an exclusive lock
// on the data file after the timeout passed to Open().
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrTimeout = errors.ErrTimeout
)
// These errors can occur when beginning or committing a Tx.
var (
// ErrTxNotWritable is returned when performing a write operation on a
// read-only transaction.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrTxNotWritable = errors.ErrTxNotWritable
// ErrTxClosed is returned when committing or rolling back a transaction
// that has already been committed or rolled back.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrTxClosed = errors.ErrTxClosed
// ErrDatabaseReadOnly is returned when a mutating transaction is started on a
// read-only database.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrDatabaseReadOnly = errors.ErrDatabaseReadOnly
// ErrFreePagesNotLoaded is returned when a readonly transaction without
// preloading the free pages is trying to access the free pages.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrFreePagesNotLoaded = errors.ErrFreePagesNotLoaded
)
// These errors can occur when putting or deleting a value or a bucket.
var (
// ErrBucketNotFound is returned when trying to access a bucket that has
// not been created yet.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrBucketNotFound = errors.ErrBucketNotFound
// ErrBucketExists is returned when creating a bucket that already exists.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrBucketExists = errors.ErrBucketExists
// ErrBucketNameRequired is returned when creating a bucket with a blank name.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrBucketNameRequired = errors.ErrBucketNameRequired
// ErrKeyRequired is returned when inserting a zero-length key.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrKeyRequired = errors.ErrKeyRequired
// ErrKeyTooLarge is returned when inserting a key that is larger than MaxKeySize.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrKeyTooLarge = errors.ErrKeyTooLarge
// ErrValueTooLarge is returned when inserting a value that is larger than MaxValueSize.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrValueTooLarge = errors.ErrValueTooLarge
// ErrIncompatibleValue is returned when trying create or delete a bucket
// on an existing non-bucket key or when trying to create or delete a
// non-bucket key on an existing bucket key.
//
// Deprecated: Use the error variables defined in the bbolt/errors package.
ErrIncompatibleValue = errors.ErrIncompatibleValue
)

View File

@ -1,4 +1,6 @@
package common
// Package errors defines the error variables that may be returned
// during bbolt operations.
package errors
import "errors"

View File

@ -5,6 +5,8 @@ import (
"hash/fnv"
"io"
"unsafe"
"go.etcd.io/bbolt/errors"
)
type Meta struct {
@ -22,11 +24,11 @@ type Meta struct {
// Validate checks the marker bytes and version of the meta page to ensure it matches this binary.
func (m *Meta) Validate() error {
if m.magic != Magic {
return ErrInvalid
return errors.ErrInvalid
} else if m.version != Version {
return ErrVersionMismatch
return errors.ErrVersionMismatch
} else if m.checksum != m.Sum64() {
return ErrChecksum
return errors.ErrChecksum
}
return nil
}

11
tx.go
View File

@ -10,6 +10,7 @@ import (
"time"
"unsafe"
"go.etcd.io/bbolt/errors"
"go.etcd.io/bbolt/internal/common"
)
@ -141,9 +142,9 @@ func (tx *Tx) OnCommit(fn func()) {
func (tx *Tx) Commit() error {
common.Assert(!tx.managed, "managed tx commit not allowed")
if tx.db == nil {
return common.ErrTxClosed
return errors.ErrTxClosed
} else if !tx.writable {
return common.ErrTxNotWritable
return errors.ErrTxNotWritable
}
// TODO(benbjohnson): Use vectorized I/O to write out dirty pages.
@ -253,7 +254,7 @@ func (tx *Tx) commitFreelist() error {
func (tx *Tx) Rollback() error {
common.Assert(!tx.managed, "managed tx rollback not allowed")
if tx.db == nil {
return common.ErrTxClosed
return errors.ErrTxClosed
}
tx.nonPhysicalRollback()
return nil
@ -560,13 +561,13 @@ func (tx *Tx) forEachPageInternal(pgidstack []common.Pgid, fn func(*common.Page,
// This is only safe for concurrent use when used by a writable transaction.
func (tx *Tx) Page(id int) (*common.PageInfo, error) {
if tx.db == nil {
return nil, common.ErrTxClosed
return nil, errors.ErrTxClosed
} else if common.Pgid(id) >= tx.meta.Pgid() {
return nil, nil
}
if tx.db.freelist == nil {
return nil, common.ErrFreePagesNotLoaded
return nil, errors.ErrFreePagesNotLoaded
}
// Build the page info.

View File

@ -14,8 +14,8 @@ import (
"github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt"
berrors "go.etcd.io/bbolt/errors"
"go.etcd.io/bbolt/internal/btesting"
"go.etcd.io/bbolt/internal/common"
)
// TestTx_Check_ReadOnly tests consistency checking on a ReadOnly database.
@ -85,7 +85,7 @@ func TestTx_Commit_ErrTxClosed(t *testing.T) {
t.Fatal(err)
}
if err := tx.Commit(); err != common.ErrTxClosed {
if err := tx.Commit(); err != berrors.ErrTxClosed {
t.Fatalf("unexpected error: %s", err)
}
}
@ -102,7 +102,7 @@ func TestTx_Rollback_ErrTxClosed(t *testing.T) {
if err := tx.Rollback(); err != nil {
t.Fatal(err)
}
if err := tx.Rollback(); err != common.ErrTxClosed {
if err := tx.Rollback(); err != berrors.ErrTxClosed {
t.Fatalf("unexpected error: %s", err)
}
}
@ -114,7 +114,7 @@ func TestTx_Commit_ErrTxNotWritable(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err := tx.Commit(); err != common.ErrTxNotWritable {
if err := tx.Commit(); err != berrors.ErrTxNotWritable {
t.Fatal(err)
}
// Close the view transaction
@ -166,7 +166,7 @@ func TestTx_CreateBucket_ErrTxNotWritable(t *testing.T) {
db := btesting.MustCreateDB(t)
if err := db.View(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("foo"))
if err != common.ErrTxNotWritable {
if err != berrors.ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -186,7 +186,7 @@ func TestTx_CreateBucket_ErrTxClosed(t *testing.T) {
t.Fatal(err)
}
if _, err := tx.CreateBucket([]byte("foo")); err != common.ErrTxClosed {
if _, err := tx.CreateBucket([]byte("foo")); err != berrors.ErrTxClosed {
t.Fatalf("unexpected error: %s", err)
}
}
@ -294,11 +294,11 @@ func TestTx_CreateBucketIfNotExists(t *testing.T) {
func TestTx_CreateBucketIfNotExists_ErrBucketNameRequired(t *testing.T) {
db := btesting.MustCreateDB(t)
if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucketIfNotExists([]byte{}); err != common.ErrBucketNameRequired {
if _, err := tx.CreateBucketIfNotExists([]byte{}); err != berrors.ErrBucketNameRequired {
t.Fatalf("unexpected error: %s", err)
}
if _, err := tx.CreateBucketIfNotExists(nil); err != common.ErrBucketNameRequired {
if _, err := tx.CreateBucketIfNotExists(nil); err != berrors.ErrBucketNameRequired {
t.Fatalf("unexpected error: %s", err)
}
@ -324,7 +324,7 @@ func TestTx_CreateBucket_ErrBucketExists(t *testing.T) {
// Create the same bucket again.
if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucket([]byte("widgets")); err != common.ErrBucketExists {
if _, err := tx.CreateBucket([]byte("widgets")); err != berrors.ErrBucketExists {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -337,7 +337,7 @@ func TestTx_CreateBucket_ErrBucketExists(t *testing.T) {
func TestTx_CreateBucket_ErrBucketNameRequired(t *testing.T) {
db := btesting.MustCreateDB(t)
if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucket(nil); err != common.ErrBucketNameRequired {
if _, err := tx.CreateBucket(nil); err != berrors.ErrBucketNameRequired {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -402,7 +402,7 @@ func TestTx_DeleteBucket_ErrTxClosed(t *testing.T) {
if err := tx.Commit(); err != nil {
t.Fatal(err)
}
if err := tx.DeleteBucket([]byte("foo")); err != common.ErrTxClosed {
if err := tx.DeleteBucket([]byte("foo")); err != berrors.ErrTxClosed {
t.Fatalf("unexpected error: %s", err)
}
}
@ -411,7 +411,7 @@ func TestTx_DeleteBucket_ErrTxClosed(t *testing.T) {
func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
db := btesting.MustCreateDB(t)
if err := db.View(func(tx *bolt.Tx) error {
if err := tx.DeleteBucket([]byte("foo")); err != common.ErrTxNotWritable {
if err := tx.DeleteBucket([]byte("foo")); err != berrors.ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
}
return nil
@ -424,7 +424,7 @@ func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
func TestTx_DeleteBucket_NotFound(t *testing.T) {
db := btesting.MustCreateDB(t)
if err := db.Update(func(tx *bolt.Tx) error {
if err := tx.DeleteBucket([]byte("widgets")); err != common.ErrBucketNotFound {
if err := tx.DeleteBucket([]byte("widgets")); err != berrors.ErrBucketNotFound {
t.Fatalf("unexpected error: %s", err)
}
return nil