mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Merge pull request #514 from cenkalti/prevNode
feat(prevNode): add "prevNode" to "Set" response
This commit is contained in:
commit
2a2714a4bf
@ -1,6 +1,7 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,6 +20,40 @@ type NodeExtern struct {
|
|||||||
CreatedIndex uint64 `json:"createdIndex,omitempty"`
|
CreatedIndex uint64 `json:"createdIndex,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (eNode *NodeExtern) loadInternalNode(n *node, recursive, sorted bool) {
|
||||||
|
if n.IsDir() { // node is a directory
|
||||||
|
eNode.Dir = true
|
||||||
|
|
||||||
|
children, _ := n.List()
|
||||||
|
eNode.Nodes = make(NodeExterns, len(children))
|
||||||
|
|
||||||
|
// we do not use the index in the children slice directly
|
||||||
|
// we need to skip the hidden one
|
||||||
|
i := 0
|
||||||
|
|
||||||
|
for _, child := range children {
|
||||||
|
if child.IsHidden() { // get will not return hidden nodes
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
eNode.Nodes[i] = child.Repr(recursive, sorted)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
// eliminate hidden nodes
|
||||||
|
eNode.Nodes = eNode.Nodes[:i]
|
||||||
|
|
||||||
|
if sorted {
|
||||||
|
sort.Sort(eNode.Nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // node is a file
|
||||||
|
eNode.Value, _ = n.Read()
|
||||||
|
}
|
||||||
|
|
||||||
|
eNode.Expiration, eNode.TTL = n.ExpirationAndTTL()
|
||||||
|
}
|
||||||
|
|
||||||
type NodeExterns []*NodeExtern
|
type NodeExterns []*NodeExtern
|
||||||
|
|
||||||
// interfaces for sorting
|
// interfaces for sorting
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -119,39 +118,7 @@ func (s *store) Get(nodePath string, recursive, sorted bool) (*Event, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e := newEvent(Get, nodePath, n.ModifiedIndex, n.CreatedIndex)
|
e := newEvent(Get, nodePath, n.ModifiedIndex, n.CreatedIndex)
|
||||||
eNode := e.Node
|
e.Node.loadInternalNode(n, recursive, sorted)
|
||||||
|
|
||||||
if n.IsDir() { // node is a directory
|
|
||||||
eNode.Dir = true
|
|
||||||
|
|
||||||
children, _ := n.List()
|
|
||||||
eNode.Nodes = make(NodeExterns, len(children))
|
|
||||||
|
|
||||||
// we do not use the index in the children slice directly
|
|
||||||
// we need to skip the hidden one
|
|
||||||
i := 0
|
|
||||||
|
|
||||||
for _, child := range children {
|
|
||||||
if child.IsHidden() { // get will not return hidden nodes
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
eNode.Nodes[i] = child.Repr(recursive, sorted)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
// eliminate hidden nodes
|
|
||||||
eNode.Nodes = eNode.Nodes[:i]
|
|
||||||
|
|
||||||
if sorted {
|
|
||||||
sort.Sort(eNode.Nodes)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else { // node is a file
|
|
||||||
eNode.Value, _ = n.Read()
|
|
||||||
}
|
|
||||||
|
|
||||||
eNode.Expiration, eNode.TTL = n.ExpirationAndTTL()
|
|
||||||
|
|
||||||
s.Stats.Inc(GetSuccess)
|
s.Stats.Inc(GetSuccess)
|
||||||
|
|
||||||
@ -177,17 +144,40 @@ func (s *store) Create(nodePath string, dir bool, value string, unique bool, exp
|
|||||||
|
|
||||||
// Set creates or replace the node at nodePath.
|
// Set creates or replace the node at nodePath.
|
||||||
func (s *store) Set(nodePath string, dir bool, value string, expireTime time.Time) (*Event, error) {
|
func (s *store) Set(nodePath string, dir bool, value string, expireTime time.Time) (*Event, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
s.worldLock.Lock()
|
s.worldLock.Lock()
|
||||||
defer s.worldLock.Unlock()
|
defer s.worldLock.Unlock()
|
||||||
e, err := s.internalCreate(nodePath, dir, value, false, true, expireTime, Set)
|
|
||||||
|
|
||||||
if err == nil {
|
defer func() {
|
||||||
s.Stats.Inc(SetSuccess)
|
if err == nil {
|
||||||
} else {
|
s.Stats.Inc(SetSuccess)
|
||||||
s.Stats.Inc(SetFail)
|
} else {
|
||||||
|
s.Stats.Inc(SetFail)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Get prevNode value
|
||||||
|
n, getErr := s.internalGet(nodePath)
|
||||||
|
if getErr != nil && getErr.ErrorCode != etcdErr.EcodeKeyNotFound {
|
||||||
|
err = getErr
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return e, err
|
// Set new value
|
||||||
|
e, err := s.internalCreate(nodePath, dir, value, false, true, expireTime, Set)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put prevNode into event
|
||||||
|
if getErr == nil {
|
||||||
|
prev := newEvent(Get, nodePath, n.ModifiedIndex, n.CreatedIndex)
|
||||||
|
prev.Node.loadInternalNode(n, false, false)
|
||||||
|
e.PrevNode = prev.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) CompareAndSwap(nodePath string, prevValue string, prevIndex uint64,
|
func (s *store) CompareAndSwap(nodePath string, prevValue string, prevIndex uint64,
|
||||||
|
@ -115,6 +115,22 @@ func TestSet(t *testing.T) {
|
|||||||
assert.Equal(t, e.PrevNode.Key, "/foo", "")
|
assert.Equal(t, e.PrevNode.Key, "/foo", "")
|
||||||
assert.Equal(t, e.PrevNode.Value, "", "")
|
assert.Equal(t, e.PrevNode.Value, "", "")
|
||||||
assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(1), "")
|
assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(1), "")
|
||||||
|
// Set /foo="baz" (for testing prevNode)
|
||||||
|
e, err = s.Set("/foo", false, "baz", Permanent)
|
||||||
|
assert.Nil(t, err, "")
|
||||||
|
assert.Equal(t, e.Action, "set", "")
|
||||||
|
assert.Equal(t, e.Node.Key, "/foo", "")
|
||||||
|
assert.False(t, e.Node.Dir, "")
|
||||||
|
assert.Equal(t, e.Node.Value, "baz", "")
|
||||||
|
assert.Nil(t, e.Node.Nodes, "")
|
||||||
|
assert.Nil(t, e.Node.Expiration, "")
|
||||||
|
assert.Equal(t, e.Node.TTL, 0, "")
|
||||||
|
assert.Equal(t, e.Node.ModifiedIndex, uint64(3), "")
|
||||||
|
// check prevNode
|
||||||
|
assert.NotNil(t, e.PrevNode, "")
|
||||||
|
assert.Equal(t, e.PrevNode.Key, "/foo", "")
|
||||||
|
assert.Equal(t, e.PrevNode.Value, "bar", "")
|
||||||
|
assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(2), "")
|
||||||
|
|
||||||
// Set /dir as a directory
|
// Set /dir as a directory
|
||||||
e, err = s.Set("/dir", true, "", Permanent)
|
e, err = s.Set("/dir", true, "", Permanent)
|
||||||
@ -126,7 +142,7 @@ func TestSet(t *testing.T) {
|
|||||||
assert.Nil(t, e.Node.Nodes, "")
|
assert.Nil(t, e.Node.Nodes, "")
|
||||||
assert.Nil(t, e.Node.Expiration, "")
|
assert.Nil(t, e.Node.Expiration, "")
|
||||||
assert.Equal(t, e.Node.TTL, 0, "")
|
assert.Equal(t, e.Node.TTL, 0, "")
|
||||||
assert.Equal(t, e.Node.ModifiedIndex, uint64(3), "")
|
assert.Equal(t, e.Node.ModifiedIndex, uint64(4), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the store can create a new key if it doesn't already exist.
|
// Ensure that the store can create a new key if it doesn't already exist.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user