Merge pull request #4 from benbjohnson/api

Clean up API.
pull/34/head
Ben Johnson 2014-01-31 09:27:18 -08:00
commit b17d078d4f
10 changed files with 126 additions and 58 deletions

View File

@ -1,7 +1,5 @@
package bolt package bolt
const MaxBucketNameSize = 255
type Bucket struct { type Bucket struct {
*bucket *bucket
name string name string

View File

@ -1,8 +1,9 @@
package bolt package bolt
const Version = 1 const version = 1
const ( const (
MaxKeySize = 0x8000 MaxBucketNameSize = 255
MaxDataSize = 0xffffffff MaxKeySize = 32768
MaxDataSize = 4294967295
) )

96
db.go
View File

@ -14,12 +14,6 @@ const (
const minPageSize = 0x1000 const minPageSize = 0x1000
var (
DatabaseNotOpenError = &Error{"db is not open", nil}
DatabaseAlreadyOpenedError = &Error{"db already open", nil}
TransactionInProgressError = &Error{"writable transaction is already in progress", nil}
)
type DB struct { type DB struct {
sync.Mutex sync.Mutex
opened bool opened bool
@ -157,9 +151,9 @@ func (db *DB) init() error {
// Initialize the meta page. // Initialize the meta page.
m := p.meta() m := p.meta()
m.magic = magic m.magic = magic
m.version = Version m.version = version
m.pageSize = uint32(db.pageSize) m.pageSize = uint32(db.pageSize)
m.version = Version m.version = version
m.free = 2 m.free = 2
m.sys = 3 m.sys = 3
m.pgid = 4 m.pgid = 4
@ -239,6 +233,92 @@ func (db *DB) RWTransaction() (*RWTransaction, error) {
return t, nil return t, nil
} }
// Bucket retrieves a reference to a bucket.
func (db *DB) Bucket(name string) (*Bucket, error) {
t, err := db.Transaction()
if err != nil {
return nil, err
}
defer t.Close()
return t.Bucket(name), nil
}
// Buckets retrieves a list of all buckets in the database.
func (db *DB) Buckets() ([]*Bucket, error) {
t, err := db.Transaction()
if err != nil {
return nil, err
}
defer t.Close()
return t.Buckets(), nil
}
// CreateBucket creates a new bucket in the database.
func (db *DB) CreateBucket(name string) error {
t, err := db.RWTransaction()
if err != nil {
return err
}
if err := t.CreateBucket(name); err != nil {
t.Rollback()
return err
}
return t.Commit()
}
// DeleteBucket removes a bucket from the database.
func (db *DB) DeleteBucket(name string) error {
t, err := db.RWTransaction()
if err != nil {
return err
}
if err := t.DeleteBucket(name); err != nil {
t.Rollback()
return err
}
return t.Commit()
}
// Get retrieves the value for a key in a bucket.
func (db *DB) Get(name string, key []byte) ([]byte, error) {
t, err := db.Transaction()
if err != nil {
return nil, err
}
defer t.Close()
return t.Get(name, key), nil
}
// Put sets the value for a key in a bucket.
func (db *DB) Put(name string, key []byte, value []byte) error {
t, err := db.RWTransaction()
if err != nil {
return err
}
if err := t.Put(name, key, value); err != nil {
t.Rollback()
return err
}
return t.Commit()
}
// Delete removes a key from a bucket.
func (db *DB) Delete(name string, key []byte) error {
t, err := db.RWTransaction()
if err != nil {
return err
}
if err := t.Delete(name, key); err != nil {
t.Rollback()
return err
}
return t.Commit()
}
// page retrieves a page reference from the mmap based on the current page size. // page retrieves a page reference from the mmap based on the current page size.
func (db *DB) page(id pgid) *page { func (db *DB) page(id pgid) *page {
return (*page)(unsafe.Pointer(&db.data[id*pgid(db.pageSize)])) return (*page)(unsafe.Pointer(&db.data[id*pgid(db.pageSize)]))

View File

@ -123,16 +123,16 @@ func TestDBCorruptMeta0(t *testing.T) {
withMockDB(func(db *DB, mockos *mockos, mocksyscall *mocksyscall, path string) { withMockDB(func(db *DB, mockos *mockos, mocksyscall *mocksyscall, path string) {
var m meta var m meta
m.magic = magic m.magic = magic
m.version = Version m.version = version
m.pageSize = 0x8000 m.pageSize = 0x8000
// Create a file with bad magic. // Create a file with bad magic.
b := make([]byte, 0x10000) b := make([]byte, 0x10000)
p0, p1 := (*page)(unsafe.Pointer(&b[0x0000])), (*page)(unsafe.Pointer(&b[0x8000])) p0, p1 := (*page)(unsafe.Pointer(&b[0x0000])), (*page)(unsafe.Pointer(&b[0x8000]))
p0.meta().magic = 0 p0.meta().magic = 0
p0.meta().version = Version p0.meta().version = version
p1.meta().magic = magic p1.meta().magic = magic
p1.meta().version = Version p1.meta().version = version
// Mock file access. // Mock file access.
file, metafile := &mockfile{}, &mockfile{} file, metafile := &mockfile{}, &mockfile{}

3
doc.go Normal file
View File

@ -0,0 +1,3 @@
package bolt
// TODO(benbjohnson)

View File

@ -1,5 +1,15 @@
package bolt package bolt
var (
InvalidError = &Error{"Invalid database", nil}
VersionMismatchError = &Error{"version mismatch", nil}
DatabaseNotOpenError = &Error{"db is not open", nil}
DatabaseAlreadyOpenedError = &Error{"db already open", nil}
TransactionInProgressError = &Error{"writable transaction is already in progress", nil}
InvalidTransactionError = &Error{"txn is invalid", nil}
BucketAlreadyExistsError = &Error{"bucket already exists", nil}
)
type Error struct { type Error struct {
message string message string
cause error cause error

View File

@ -1,12 +1,6 @@
package bolt package bolt
var (
InvalidError = &Error{"Invalid database", nil}
VersionMismatchError = &Error{"version mismatch", nil}
)
const magic uint32 = 0xDEADC0DE const magic uint32 = 0xDEADC0DE
const version uint32 = 1
type meta struct { type meta struct {
magic uint32 magic uint32
@ -22,7 +16,7 @@ type meta struct {
func (m *meta) validate() error { func (m *meta) validate() error {
if m.magic != magic { if m.magic != magic {
return InvalidError return InvalidError
} else if m.version != Version { } else if m.version != version {
return VersionMismatchError return VersionMismatchError
} }
return nil return nil

View File

@ -79,7 +79,7 @@ func (t *RWTransaction) Put(name string, key []byte, value []byte) error {
return nil return nil
} }
func (t *RWTransaction) Delete(key []byte) error { func (t *RWTransaction) Delete(name string, key []byte) error {
// TODO: Traverse to the correct node. // TODO: Traverse to the correct node.
// TODO: If missing, exit. // TODO: If missing, exit.
// TODO: Remove node from page. // TODO: Remove node from page.
@ -116,17 +116,15 @@ func (t *RWTransaction) Commit() error {
return nil return nil
} }
func (t *RWTransaction) Rollback() error { func (t *RWTransaction) Rollback() {
return t.close() t.close()
} }
func (t *RWTransaction) close() error { func (t *RWTransaction) close() {
// Clear temporary pages. // Clear temporary pages.
t.leafs = nil t.leafs = nil
// TODO: Release writer lock. // TODO: Release writer lock.
return nil
} }
// allocate returns a contiguous block of memory starting at a given page. // allocate returns a contiguous block of memory starting at a given page.

View File

@ -19,28 +19,12 @@ func TestRWTransaction(t *testing.T) {
func TestTransactionCreateBucket(t *testing.T) { func TestTransactionCreateBucket(t *testing.T) {
withOpenDB(func(db *DB, path string) { withOpenDB(func(db *DB, path string) {
// Create a bucket. // Create a bucket.
txn, _ := db.RWTransaction() err := db.CreateBucket("widgets")
err := txn.CreateBucket("widgets")
assert.NoError(t, err) assert.NoError(t, err)
// Commit the transaction. // Read the bucket through a separate transaction.
err = txn.Commit() b, err := db.Bucket("widgets")
assert.NotNil(t, b)
assert.NoError(t, err) assert.NoError(t, err)
// Open a separate read-only transaction.
rtxn, err := db.Transaction()
assert.NotNil(t, txn)
assert.NoError(t, err)
b := rtxn.Bucket("widgets")
assert.NoError(t, err)
if assert.NotNil(t, b) {
assert.Equal(t, b.Name(), "widgets")
}
}) })
} }
// Ensure that an existing bucket cannot be created.
func TestTransactionCreateExistingBucket(t *testing.T) {
t.Skip("pending")
}

View File

@ -1,10 +1,5 @@
package bolt package bolt
var (
InvalidTransactionError = &Error{"txn is invalid", nil}
BucketAlreadyExistsError = &Error{"bucket already exists", nil}
)
const ( const (
ps_modify = 1 ps_modify = 1
ps_rootonly = 2 ps_rootonly = 2
@ -32,9 +27,8 @@ func (t *Transaction) init(db *DB) {
t.sys.read(t.page(t.meta.sys)) t.sys.read(t.page(t.meta.sys))
} }
func (t *Transaction) Close() error { func (t *Transaction) Close() {
// TODO: Close buckets. // TODO: Close buckets.
return nil
} }
func (t *Transaction) DB() *DB { func (t *Transaction) DB() *DB {
@ -56,6 +50,12 @@ func (t *Transaction) Bucket(name string) *Bucket {
} }
} }
// Buckets retrieves a list of all buckets.
func (t *Transaction) Buckets() []*Bucket {
warn("[pending] Transaction.Buckets()") // TODO
return nil
}
// Cursor creates a cursor associated with a given bucket. // Cursor creates a cursor associated with a given bucket.
func (t *Transaction) Cursor(name string) *Cursor { func (t *Transaction) Cursor(name string) *Cursor {
b := t.Bucket(name) b := t.Bucket(name)
@ -74,8 +74,8 @@ func (t *Transaction) Get(name string, key []byte) []byte {
return c.Get(key) return c.Get(key)
} }
// Stat returns information about a bucket's internal structure. // stat returns information about a bucket's internal structure.
func (t *Transaction) Stat(name string) *Stat { func (t *Transaction) stat(name string) *Stat {
// TODO // TODO
return nil return nil
} }