mirror of https://github.com/etcd-io/bbolt.git
Error refactoring.
Fixed up a few error issues and refactored out the Error type.pull/34/head
parent
7ea635c8fc
commit
59fde2f664
34
bucket.go
34
bucket.go
|
@ -2,6 +2,40 @@ package bolt
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrBucketNotFound is returned when trying to access a bucket that has
|
||||
// not been created yet.
|
||||
ErrBucketNotFound = errors.New("bucket not found")
|
||||
|
||||
// ErrBucketExists is returned when creating a bucket that already exists.
|
||||
ErrBucketExists = errors.New("bucket already exists")
|
||||
|
||||
// ErrBucketNameRequired is returned when creating a bucket with a blank name.
|
||||
ErrBucketNameRequired = errors.New("bucket name required")
|
||||
|
||||
// ErrBucketNameTooLarge is returned when creating a bucket with a name
|
||||
// that is longer than MaxBucketNameSize.
|
||||
ErrBucketNameTooLarge = errors.New("bucket name too large")
|
||||
|
||||
// ErrBucketNotWritable is returned when changing data on a bucket
|
||||
// reference that was created from a read-only transaction.
|
||||
ErrBucketNotWritable = errors.New("bucket not writable")
|
||||
|
||||
// ErrKeyRequired is returned when inserting a zero-length key.
|
||||
ErrKeyRequired = errors.New("key required")
|
||||
|
||||
// ErrKeyTooLarge is returned when inserting a key that is larger than MaxKeySize.
|
||||
ErrKeyTooLarge = errors.New("key too large")
|
||||
|
||||
// ErrValueTooLarge is returned when inserting a value that is larger than MaxValueSize.
|
||||
ErrValueTooLarge = errors.New("value too large")
|
||||
|
||||
// ErrSequenceOverflow is returned when the next sequence number will be
|
||||
// larger than the maximum integer size.
|
||||
ErrSequenceOverflow = errors.New("sequence overflow")
|
||||
)
|
||||
|
||||
// Bucket represents a collection of key/value pairs inside the database.
|
||||
|
|
|
@ -2,6 +2,7 @@ package bolt
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
@ -203,12 +204,12 @@ func TestBucketForEachShortCircuit(t *testing.T) {
|
|||
err := tx.Bucket("widgets").ForEach(func(k, v []byte) error {
|
||||
index++
|
||||
if bytes.Equal(k, []byte("baz")) {
|
||||
return &Error{"marker", nil}
|
||||
return errors.New("marker")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
assert.Equal(t, err, &Error{"marker", nil})
|
||||
assert.Equal(t, index, 2)
|
||||
assert.Equal(t, errors.New("marker"), err)
|
||||
assert.Equal(t, 2, index)
|
||||
return nil
|
||||
})
|
||||
})
|
||||
|
|
25
db.go
25
db.go
|
@ -1,6 +1,7 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
@ -15,6 +16,16 @@ const minMmapSize = 1 << 22 // 4MB
|
|||
// The largest step that can be taken when remapping the mmap.
|
||||
const maxMmapStep = 1 << 30 // 1GB
|
||||
|
||||
var (
|
||||
// ErrDatabaseNotOpen is returned when a DB instance is accessed before it
|
||||
// is opened or after it is closed.
|
||||
ErrDatabaseNotOpen = errors.New("database not open")
|
||||
|
||||
// ErrDatabaseOpen is returned when opening a database that is
|
||||
// already open.
|
||||
ErrDatabaseOpen = errors.New("database already open")
|
||||
)
|
||||
|
||||
// DB represents a collection of buckets persisted to a file on disk.
|
||||
// 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.
|
||||
|
@ -89,7 +100,7 @@ func (db *DB) Open(path string, mode os.FileMode) error {
|
|||
|
||||
// Initialize the database if it doesn't exist.
|
||||
if info, err := db.file.Stat(); err != nil {
|
||||
return &Error{"stat error", err}
|
||||
return fmt.Errorf("stat error: %s", err)
|
||||
} else if info.Size() == 0 {
|
||||
// Initialize new files with meta pages.
|
||||
if err := db.init(); err != nil {
|
||||
|
@ -101,7 +112,7 @@ func (db *DB) Open(path string, mode os.FileMode) error {
|
|||
if _, err := db.file.ReadAt(buf[:], 0); err == nil {
|
||||
m := db.pageInBuffer(buf[:], 0).meta()
|
||||
if err := m.validate(); err != nil {
|
||||
return &Error{"meta error", err}
|
||||
return fmt.Errorf("meta error: %s", err)
|
||||
}
|
||||
db.pageSize = int(m.pageSize)
|
||||
}
|
||||
|
@ -140,9 +151,9 @@ func (db *DB) mmap(minsz int) error {
|
|||
|
||||
info, err := db.file.Stat()
|
||||
if err != nil {
|
||||
return &Error{"mmap stat error", err}
|
||||
return fmt.Errorf("mmap stat error: %s", err)
|
||||
} else if int(info.Size()) < db.pageSize*2 {
|
||||
return &Error{"file size too small", err}
|
||||
return fmt.Errorf("file size too small")
|
||||
}
|
||||
|
||||
// Ensure the size is at least the minimum size.
|
||||
|
@ -163,10 +174,10 @@ func (db *DB) mmap(minsz int) error {
|
|||
|
||||
// Validate the meta pages.
|
||||
if err := db.meta0.validate(); err != nil {
|
||||
return &Error{"meta0 error", err}
|
||||
return fmt.Errorf("meta0 error: %s", err)
|
||||
}
|
||||
if err := db.meta1.validate(); err != nil {
|
||||
return &Error{"meta1 error", err}
|
||||
return fmt.Errorf("meta1 error: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -529,7 +540,7 @@ func (db *DB) allocate(count int) (*page, error) {
|
|||
var minsz = int((p.id+pgid(count))+1) * db.pageSize
|
||||
if minsz >= len(db.data) {
|
||||
if err := db.mmap(minsz); err != nil {
|
||||
return nil, &Error{"mmap allocate error", err}
|
||||
return nil, fmt.Errorf("mmap allocate error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
29
db_test.go
29
db_test.go
|
@ -1,6 +1,7 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
|
@ -8,6 +9,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -53,14 +55,12 @@ func TestDBReopen(t *testing.T) {
|
|||
|
||||
// Ensure that the database returns an error if the file handle cannot be open.
|
||||
func TestDBOpenFileError(t *testing.T) {
|
||||
withDBFile(func(db *DB, path string) {
|
||||
exp := &os.PathError{
|
||||
Op: "open",
|
||||
Path: path + "/youre-not-my-real-parent",
|
||||
Err: syscall.ENOTDIR,
|
||||
}
|
||||
withDB(func(db *DB, path string) {
|
||||
err := db.Open(path+"/youre-not-my-real-parent", 0666)
|
||||
assert.Equal(t, err, exp)
|
||||
if err, _ := err.(*os.PathError); assert.Error(t, err) {
|
||||
assert.Equal(t, path+"/youre-not-my-real-parent", err.Path)
|
||||
assert.Equal(t, "open", err.Op)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -78,13 +78,14 @@ func TestDBMetaInitWriteError(t *testing.T) {
|
|||
|
||||
// Ensure that a database that is too small returns an error.
|
||||
func TestDBFileTooSmall(t *testing.T) {
|
||||
withDBFile(func(db *DB, path string) {
|
||||
// corrupt the database
|
||||
err := os.Truncate(path, int64(os.Getpagesize()))
|
||||
assert.NoError(t, err)
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
db.Close()
|
||||
|
||||
err = db.Open(path, 0666)
|
||||
assert.Equal(t, err, &Error{"file size too small", nil})
|
||||
// corrupt the database
|
||||
assert.NoError(t, os.Truncate(path, int64(os.Getpagesize())))
|
||||
|
||||
err := db.Open(path, 0666)
|
||||
assert.Equal(t, errors.New("file size too small"), err)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -108,7 +109,7 @@ func TestDBCorruptMeta0(t *testing.T) {
|
|||
|
||||
// Open the database.
|
||||
err = db.Open(path, 0666)
|
||||
assert.Equal(t, err, &Error{"meta error", ErrInvalid})
|
||||
assert.Equal(t, err, errors.New("meta error: invalid database"))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
71
error.go
71
error.go
|
@ -1,71 +0,0 @@
|
|||
package bolt
|
||||
|
||||
var (
|
||||
// ErrInvalid is returned when a data file is not a Bolt-formatted database.
|
||||
ErrInvalid = &Error{"Invalid database", nil}
|
||||
|
||||
// ErrVersionMismatch is returned when the data file was created with a
|
||||
// different version of Bolt.
|
||||
ErrVersionMismatch = &Error{"version mismatch", nil}
|
||||
|
||||
// ErrDatabaseNotOpen is returned when a DB instance is accessed before it
|
||||
// is opened or after it is closed.
|
||||
ErrDatabaseNotOpen = &Error{"database not open", nil}
|
||||
|
||||
// ErrDatabaseOpen is returned when opening a database that is
|
||||
// already open.
|
||||
ErrDatabaseOpen = &Error{"database already open", nil}
|
||||
|
||||
// ErrTxNotWritable is returned when performing a write operation on a
|
||||
// read-only transaction.
|
||||
ErrTxNotWritable = &Error{"tx not writable", nil}
|
||||
|
||||
// ErrTxClosed is returned when committing or rolling back a transaction
|
||||
// that has already been committed or rolled back.
|
||||
ErrTxClosed = &Error{"tx closed", nil}
|
||||
|
||||
// ErrBucketNotFound is returned when trying to access a bucket that has
|
||||
// not been created yet.
|
||||
ErrBucketNotFound = &Error{"bucket not found", nil}
|
||||
|
||||
// ErrBucketExists is returned when creating a bucket that already exists.
|
||||
ErrBucketExists = &Error{"bucket already exists", nil}
|
||||
|
||||
// ErrBucketNameRequired is returned when creating a bucket with a blank name.
|
||||
ErrBucketNameRequired = &Error{"bucket name required", nil}
|
||||
|
||||
// ErrBucketNameTooLarge is returned when creating a bucket with a name
|
||||
// that is longer than MaxBucketNameSize.
|
||||
ErrBucketNameTooLarge = &Error{"bucket name too large", nil}
|
||||
|
||||
// ErrBucketNotWritable is returned when changing data on a bucket
|
||||
// reference that was created from a read-only transaction.
|
||||
ErrBucketNotWritable = &Error{"bucket not writable", nil}
|
||||
|
||||
// ErrKeyRequired is returned when inserting a zero-length key.
|
||||
ErrKeyRequired = &Error{"key required", nil}
|
||||
|
||||
// ErrKeyTooLarge is returned when inserting a key that is larger than MaxKeySize.
|
||||
ErrKeyTooLarge = &Error{"key too large", nil}
|
||||
|
||||
// ErrValueTooLarge is returned when inserting a value that is larger than MaxValueSize.
|
||||
ErrValueTooLarge = &Error{"value too large", nil}
|
||||
|
||||
// ErrSequenceOverflow is returned when the next sequence number will be
|
||||
// larger than the maximum integer size.
|
||||
ErrSequenceOverflow = &Error{"sequence overflow", nil}
|
||||
)
|
||||
|
||||
// Error represents an error condition caused by Bolt.
|
||||
type Error struct {
|
||||
message string
|
||||
cause error
|
||||
}
|
||||
|
||||
// Error returns a string representation of the error.
|
||||
func (e *Error) Error() string {
|
||||
if e.cause != nil {
|
||||
return e.message + ": " + e.cause.Error()
|
||||
}
|
||||
return e.message
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Ensure that nested errors are appropriately formatted.
|
||||
func TestError(t *testing.T) {
|
||||
e := &Error{"one error", &Error{"two error", nil}}
|
||||
assert.Equal(t, e.Error(), "one error: two error")
|
||||
}
|
13
meta.go
13
meta.go
|
@ -1,7 +1,20 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
const magic uint32 = 0xED0CDAED
|
||||
|
||||
var (
|
||||
// ErrInvalid is returned when a data file is not a Bolt-formatted database.
|
||||
ErrInvalid = errors.New("invalid database")
|
||||
|
||||
// ErrVersionMismatch is returned when the data file was created with a
|
||||
// different version of Bolt.
|
||||
ErrVersionMismatch = errors.New("version mismatch")
|
||||
)
|
||||
|
||||
type meta struct {
|
||||
magic uint32
|
||||
version uint32
|
||||
|
|
11
tx.go
11
tx.go
|
@ -1,10 +1,21 @@
|
|||
package bolt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrTxNotWritable is returned when performing a write operation on a
|
||||
// read-only transaction.
|
||||
ErrTxNotWritable = errors.New("tx not writable")
|
||||
|
||||
// ErrTxClosed is returned when committing or rolling back a transaction
|
||||
// that has already been committed or rolled back.
|
||||
ErrTxClosed = errors.New("tx closed")
|
||||
)
|
||||
|
||||
// txid represents the internal transaction identifier.
|
||||
type txid uint64
|
||||
|
||||
|
|
Loading…
Reference in New Issue