From 3ec700442147ead0dddf0dc1ebc21d9b164545d3 Mon Sep 17 00:00:00 2001 From: Cenk Alti Date: Wed, 29 Jan 2014 17:30:33 -0800 Subject: [PATCH 1/2] feat(prevNode): add "prevNode" to "Set" response --- store/node_extern.go | 35 ++++++++++++++++++++++ store/store.go | 70 +++++++++++++++++++------------------------- 2 files changed, 65 insertions(+), 40 deletions(-) diff --git a/store/node_extern.go b/store/node_extern.go index 1466ea16a..f1ae45c88 100644 --- a/store/node_extern.go +++ b/store/node_extern.go @@ -1,6 +1,7 @@ package store import ( + "sort" "time" ) @@ -19,6 +20,40 @@ type NodeExtern struct { 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 // interfaces for sorting diff --git a/store/store.go b/store/store.go index 05f6626cc..20e45033e 100644 --- a/store/store.go +++ b/store/store.go @@ -20,7 +20,6 @@ import ( "encoding/json" "fmt" "path" - "sort" "strconv" "strings" "sync" @@ -119,39 +118,7 @@ func (s *store) Get(nodePath string, recursive, sorted bool) (*Event, error) { } e := newEvent(Get, nodePath, n.ModifiedIndex, n.CreatedIndex) - eNode := e.Node - - 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() + e.Node.loadInternalNode(n, recursive, sorted) s.Stats.Inc(GetSuccess) @@ -177,17 +144,40 @@ func (s *store) Create(nodePath string, dir bool, value string, unique bool, exp // Set function creates or replace the node at nodePath. func (s *store) Set(nodePath string, dir bool, value string, expireTime time.Time) (*Event, error) { + var err error + s.worldLock.Lock() defer s.worldLock.Unlock() - e, err := s.internalCreate(nodePath, dir, value, false, true, expireTime, Set) - if err == nil { - s.Stats.Inc(SetSuccess) - } else { - s.Stats.Inc(SetFail) + defer func() { + if err == nil { + s.Stats.Inc(SetSuccess) + } 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, From 354a91290eac8956508eff8c24ec9344dea5ce0d Mon Sep 17 00:00:00 2001 From: Cenk Alti Date: Wed, 29 Jan 2014 17:52:25 -0800 Subject: [PATCH 2/2] feat(prevNode): add test for prevNode --- store/store_test.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/store/store_test.go b/store/store_test.go index 0a7e49e4f..66a56cc0b 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -115,6 +115,22 @@ func TestSet(t *testing.T) { assert.Equal(t, e.PrevNode.Key, "/foo", "") assert.Equal(t, e.PrevNode.Value, "", "") 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 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.Expiration, "") 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.