mirror of https://github.com/hak5/bolt.git
Remove RWCursor.
parent
73ab1d420d
commit
2c6b8e0ebf
56
README.md
56
README.md
|
@ -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 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
|
||||
|
@ -111,13 +137,6 @@ t, err := db.Transaction()
|
|||
c, err := b.Cursor("widgets")
|
||||
```
|
||||
|
||||
#### Creating a read/write cursor
|
||||
|
||||
```go
|
||||
t, err := db.RWTransaction()
|
||||
c, err := t.RWCursor("widgets")
|
||||
```
|
||||
|
||||
#### Iterating over a cursor
|
||||
|
||||
```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
|
||||
|
||||
|
|
106
rwcursor.go
106
rwcursor.go
|
@ -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
|
||||
}
|
|
@ -127,6 +127,105 @@ func (t *RWTransaction) DeleteBucket(name string) error {
|
|||
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.
|
||||
func (t *RWTransaction) allocate(count int) (*page, error) {
|
||||
// TODO: Find a continuous block of free pages.
|
||||
|
|
Loading…
Reference in New Issue