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
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
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
|
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.
|
||||||
|
|
Loading…
Reference in New Issue