144 lines
3.7 KiB
Go
144 lines
3.7 KiB
Go
|
package etcd
|
||
|
|
||
|
// readWriteCursor holds a reference to the cursors bucket, the value
|
||
|
// prefix and the current key used while iterating.
|
||
|
type readWriteCursor struct {
|
||
|
// bucket holds the reference to the parent bucket.
|
||
|
bucket *readWriteBucket
|
||
|
|
||
|
// prefix holds the value prefix which is in front of each
|
||
|
// value key in the bucket.
|
||
|
prefix string
|
||
|
|
||
|
// currKey holds the current key of the cursor.
|
||
|
currKey string
|
||
|
}
|
||
|
|
||
|
func newReadWriteCursor(bucket *readWriteBucket) *readWriteCursor {
|
||
|
return &readWriteCursor{
|
||
|
bucket: bucket,
|
||
|
prefix: string(makeValuePrefix(bucket.id)),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// First positions the cursor at the first key/value pair and returns
|
||
|
// the pair.
|
||
|
func (c *readWriteCursor) First() (key, value []byte) {
|
||
|
// Get the first key with the value prefix.
|
||
|
kv, err := c.bucket.tx.stm.First(c.prefix)
|
||
|
if err != nil {
|
||
|
// TODO: revise this once kvdb interface supports errors
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
if kv != nil {
|
||
|
c.currKey = kv.key
|
||
|
// Chop the prefix and return the key/value.
|
||
|
return []byte(kv.key[len(c.prefix):]), []byte(kv.val)
|
||
|
}
|
||
|
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
// Last positions the cursor at the last key/value pair and returns the
|
||
|
// pair.
|
||
|
func (c *readWriteCursor) Last() (key, value []byte) {
|
||
|
kv, err := c.bucket.tx.stm.Last(c.prefix)
|
||
|
if err != nil {
|
||
|
// TODO: revise this once kvdb interface supports errors
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
if kv != nil {
|
||
|
c.currKey = kv.key
|
||
|
// Chop the prefix and return the key/value.
|
||
|
return []byte(kv.key[len(c.prefix):]), []byte(kv.val)
|
||
|
}
|
||
|
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
// Next moves the cursor one key/value pair forward and returns the new
|
||
|
// pair.
|
||
|
func (c *readWriteCursor) Next() (key, value []byte) {
|
||
|
kv, err := c.bucket.tx.stm.Next(c.prefix, c.currKey)
|
||
|
if err != nil {
|
||
|
// TODO: revise this once kvdb interface supports errors
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
if kv != nil {
|
||
|
c.currKey = kv.key
|
||
|
// Chop the prefix and return the key/value.
|
||
|
return []byte(kv.key[len(c.prefix):]), []byte(kv.val)
|
||
|
}
|
||
|
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
// Prev moves the cursor one key/value pair backward and returns the new
|
||
|
// pair.
|
||
|
func (c *readWriteCursor) Prev() (key, value []byte) {
|
||
|
kv, err := c.bucket.tx.stm.Prev(c.prefix, c.currKey)
|
||
|
if err != nil {
|
||
|
// TODO: revise this once kvdb interface supports errors
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
if kv != nil {
|
||
|
c.currKey = kv.key
|
||
|
// Chop the prefix and return the key/value.
|
||
|
return []byte(kv.key[len(c.prefix):]), []byte(kv.val)
|
||
|
}
|
||
|
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
// Seek positions the cursor at the passed seek key. If the key does
|
||
|
// not exist, the cursor is moved to the next key after seek. Returns
|
||
|
// the new pair.
|
||
|
func (c *readWriteCursor) Seek(seek []byte) (key, value []byte) {
|
||
|
// Return nil if trying to seek to an empty key.
|
||
|
if seek == nil {
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
// Seek to the first key with prefix + seek. If that key is not present
|
||
|
// STM will seek to the next matching key with prefix.
|
||
|
kv, err := c.bucket.tx.stm.Seek(c.prefix, c.prefix+string(seek))
|
||
|
if err != nil {
|
||
|
// TODO: revise this once kvdb interface supports errors
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
if kv != nil {
|
||
|
c.currKey = kv.key
|
||
|
// Chop the prefix and return the key/value.
|
||
|
return []byte(kv.key[len(c.prefix):]), []byte(kv.val)
|
||
|
}
|
||
|
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
// Delete removes the current key/value pair the cursor is at without
|
||
|
// invalidating the cursor. Returns ErrIncompatibleValue if attempted
|
||
|
// when the cursor points to a nested bucket.
|
||
|
func (c *readWriteCursor) Delete() error {
|
||
|
// Get the next key after the current one. We could do this
|
||
|
// after deletion too but it's one step more efficient here.
|
||
|
nextKey, err := c.bucket.tx.stm.Next(c.prefix, c.currKey)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Delete the current key.
|
||
|
c.bucket.tx.stm.Del(c.currKey)
|
||
|
|
||
|
// Set current key to the next one if possible.
|
||
|
if nextKey != nil {
|
||
|
c.currKey = nextKey.key
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|