Remove RWCursor.

master
Ben Johnson 2014-01-26 13:22:00 -07:00
parent 73ab1d420d
commit 2c6b8e0ebf
3 changed files with 126 additions and 135 deletions

View File

@ -98,10 +98,36 @@ buckets, err := db.Buckets()
``` ```
### Key/Value Access
#### Retrieve a value for a specific key
```go
t, err := db.Transaction()
value, err := t.Get("widgets", []byte("foo"))
value, err := t.GetString("widgets", "foo")
```
#### Set the value for a key
```go
t, err := db.RWTransaction()
err := t.Put("widgets", []byte("foo"), []byte("bar"))
err := t.PutString("widgets", "foo", "bar")
```
#### Delete a given key
```go
t, err := db.RWTransaction()
err := t.Delete("widgets", []byte("foo"))
err := t.DeleteString("widgets", "foo")
```
### Cursors ### Cursors
Cursors provide access to a specific bucket within a transaction. Cursors provide fast read-only access to a specific bucket within a transaction.
#### Creating a read-only cursor #### Creating a read-only cursor
@ -111,13 +137,6 @@ t, err := db.Transaction()
c, err := b.Cursor("widgets") c, err := b.Cursor("widgets")
``` ```
#### Creating a read/write cursor
```go
t, err := db.RWTransaction()
c, err := t.RWCursor("widgets")
```
#### Iterating over a cursor #### Iterating over a cursor
```go ```go
@ -129,27 +148,6 @@ for k, v, err := c.First(); k != nil; k, v, err = c.Next() {
} }
``` ```
#### Retrieve a value for a specific key
```go
value, err := c.Get([]byte("foo"))
value, err := c.GetString("foo")
```
#### Set the value for a key (RWCursor only)
```go
err := c.Put([]byte("foo"), []byte("bar"))
err := c.PutString("foo", "bar")
```
#### Delete a given key
```go
err := c.Delete([]byte("foo"))
err := c.DeleteString("foo")
```
## Internals ## Internals

View File

@ -1,106 +0,0 @@
package bolt
// RWCursor represents a cursor that can read and write data for a bucket.
type RWCursor struct {
Cursor
transaction *RWTransaction
}
func (c *RWCursor) Put(key []byte, value []byte) error {
// Make sure this cursor was created by a transaction.
if c.transaction == nil {
return &Error{"invalid cursor", nil}
}
db := c.transaction.db
// Validate the key we're using.
if key == nil {
return &Error{"key required", nil}
} else if len(key) > db.maxKeySize {
return &Error{"key too large", nil}
}
// TODO: Validate data size based on MaxKeySize if DUPSORT.
// Validate the size of our data.
if len(data) > MaxDataSize {
return &Error{"data too large", nil}
}
// If we don't have a root page then add one.
if c.bucket.root == p_invalid {
p, err := c.newLeafPage()
if err != nil {
return err
}
c.push(p)
c.bucket.root = p.id
c.bucket.root++
// TODO: *mc->mc_dbflag |= DB_DIRTY;
// TODO? mc->mc_flags |= C_INITIALIZED;
}
// TODO: Move to key.
exists, err := c.moveTo(key)
if err != nil {
return err
}
// TODO: spill?
if err := c.spill(key, data); err != nil {
return err
}
// Make sure all cursor pages are writable
if err := c.touch(); err != nil {
return err
}
// If key does not exist the
if exists {
node := c.currentNode()
}
return nil
}
func (c *Cursor) Delete(key []byte) error {
// TODO: Traverse to the correct node.
// TODO: If missing, exit.
// TODO: Remove node from page.
// TODO: If page is empty then add it to the freelist.
return nil
}
// newLeafPage allocates and initialize new a new leaf page.
func (c *RWCursor) newLeafPage() (*page, error) {
// Allocate page.
p, err := c.allocatePage(1)
if err != nil {
return nil, err
}
// Set flags and bounds.
p.flags = p_leaf | p_dirty
p.lower = pageHeaderSize
p.upper = c.transaction.db.pageSize
return p, nil
}
// newBranchPage allocates and initialize new a new branch page.
func (b *RWCursor) newBranchPage() (*page, error) {
// Allocate page.
p, err := c.allocatePage(1)
if err != nil {
return nil, err
}
// Set flags and bounds.
p.flags = p_branch | p_dirty
p.lower = pageHeaderSize
p.upper = c.transaction.db.pageSize
return p, nil
}

View File

@ -127,6 +127,105 @@ func (t *RWTransaction) DeleteBucket(name string) error {
return nil return nil
} }
func (c *RWCursor) Put(key []byte, value []byte) error {
// Make sure this cursor was created by a transaction.
if c.transaction == nil {
return &Error{"invalid cursor", nil}
}
db := c.transaction.db
// Validate the key we're using.
if key == nil {
return &Error{"key required", nil}
} else if len(key) > db.maxKeySize {
return &Error{"key too large", nil}
}
// TODO: Validate data size based on MaxKeySize if DUPSORT.
// Validate the size of our data.
if len(data) > MaxDataSize {
return &Error{"data too large", nil}
}
// If we don't have a root page then add one.
if c.bucket.root == p_invalid {
p, err := c.newLeafPage()
if err != nil {
return err
}
c.push(p)
c.bucket.root = p.id
c.bucket.root++
// TODO: *mc->mc_dbflag |= DB_DIRTY;
// TODO? mc->mc_flags |= C_INITIALIZED;
}
// TODO: Move to key.
exists, err := c.moveTo(key)
if err != nil {
return err
}
// TODO: spill?
if err := c.spill(key, data); err != nil {
return err
}
// Make sure all cursor pages are writable
if err := c.touch(); err != nil {
return err
}
// If key does not exist the
if exists {
node := c.currentNode()
}
return nil
}
func (c *Cursor) Delete(key []byte) error {
// TODO: Traverse to the correct node.
// TODO: If missing, exit.
// TODO: Remove node from page.
// TODO: If page is empty then add it to the freelist.
return nil
}
// newLeafPage allocates and initialize new a new leaf page.
func (c *RWCursor) newLeafPage() (*page, error) {
// Allocate page.
p, err := c.allocatePage(1)
if err != nil {
return nil, err
}
// Set flags and bounds.
p.flags = p_leaf | p_dirty
p.lower = pageHeaderSize
p.upper = c.transaction.db.pageSize
return p, nil
}
// newBranchPage allocates and initialize new a new branch page.
func (b *RWCursor) newBranchPage() (*page, error) {
// Allocate page.
p, err := c.allocatePage(1)
if err != nil {
return nil, err
}
// Set flags and bounds.
p.flags = p_branch | p_dirty
p.lower = pageHeaderSize
p.upper = c.transaction.db.pageSize
return p, 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.
func (t *RWTransaction) allocate(count int) (*page, error) { func (t *RWTransaction) allocate(count int) (*page, error) {
// TODO: Find a continuous block of free pages. // TODO: Find a continuous block of free pages.