aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md52
-rw-r--r--rwcursor.go106
-rw-r--r--rwtransaction.go99
3 files changed, 124 insertions, 133 deletions
diff --git a/README.md b/README.md
index 53798f6..3a57fd0 100644
--- a/README.md
+++ b/README.md
@@ -98,56 +98,54 @@ buckets, err := db.Buckets()
```
+### Key/Value Access
-### Cursors
-
-Cursors provide access to a specific bucket within a transaction.
-
-
-#### Creating a read-only cursor
+#### Retrieve a value for a specific key
```go
t, err := db.Transaction()
-c, err := b.Cursor("widgets")
+value, err := t.Get("widgets", []byte("foo"))
+value, err := t.GetString("widgets", "foo")
```
-#### Creating a read/write cursor
+#### Set the value for a key
```go
t, err := db.RWTransaction()
-c, err := t.RWCursor("widgets")
+err := t.Put("widgets", []byte("foo"), []byte("bar"))
+err := t.PutString("widgets", "foo", "bar")
```
-#### Iterating over a cursor
+#### Delete a given key
```go
-for k, v, err := c.First(); k != nil; k, v, err = c.Next() {
- if err != nil {
- return err
- }
- ... DO SOMETHING ...
-}
+t, err := db.RWTransaction()
+err := t.Delete("widgets", []byte("foo"))
+err := t.DeleteString("widgets", "foo")
```
-#### Retrieve a value for a specific key
-```go
-value, err := c.Get([]byte("foo"))
-value, err := c.GetString("foo")
-```
+### Cursors
+
+Cursors provide fast read-only access to a specific bucket within a transaction.
-#### Set the value for a key (RWCursor only)
+
+#### Creating a read-only cursor
```go
-err := c.Put([]byte("foo"), []byte("bar"))
-err := c.PutString("foo", "bar")
+t, err := db.Transaction()
+c, err := b.Cursor("widgets")
```
-#### Delete a given key
+#### Iterating over a cursor
```go
-err := c.Delete([]byte("foo"))
-err := c.DeleteString("foo")
+for k, v, err := c.First(); k != nil; k, v, err = c.Next() {
+ if err != nil {
+ return err
+ }
+ ... DO SOMETHING ...
+}
```
diff --git a/rwcursor.go b/rwcursor.go
deleted file mode 100644
index 70fb43a..0000000
--- a/rwcursor.go
+++ /dev/null
@@ -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
-}
diff --git a/rwtransaction.go b/rwtransaction.go
index f28c8b2..2c0837f 100644
--- a/rwtransaction.go
+++ b/rwtransaction.go
@@ -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.