diff options
-rw-r--r-- | README.md | 52 | ||||
-rw-r--r-- | rwcursor.go | 106 | ||||
-rw-r--r-- | rwtransaction.go | 99 |
3 files changed, 124 insertions, 133 deletions
@@ -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. |