Browse Source

Merge pull request #1472 from jonboulle/clone_event

waitIndex is not working
Jonathan Boulle 11 years ago
parent
commit
5bba81f5fc
5 changed files with 143 additions and 3 deletions
  1. 6 3
      etcdserver/etcdhttp/client.go
  2. 9 0
      store/event.go
  3. 31 0
      store/event_test.go
  4. 26 0
      store/node_extern.go
  5. 71 0
      store/node_extern_test.go

+ 6 - 3
etcdserver/etcdhttp/client.go

@@ -474,9 +474,12 @@ func trimEventPrefix(ev *store.Event, prefix string) *store.Event {
 	if ev == nil {
 		return nil
 	}
-	ev.Node = trimNodeExternPrefix(ev.Node, prefix)
-	ev.PrevNode = trimNodeExternPrefix(ev.PrevNode, prefix)
-	return ev
+	// Since the *Event may reference one in the store history
+	// history, we must copy it before modifying
+	e := ev.Clone()
+	e.Node = trimNodeExternPrefix(e.Node, prefix)
+	e.PrevNode = trimNodeExternPrefix(e.PrevNode, prefix)
+	return e
 }
 
 func trimNodeExternPrefix(n *store.NodeExtern, prefix string) *store.NodeExtern {

+ 9 - 0
store/event.go

@@ -62,3 +62,12 @@ func (e *Event) IsCreated() bool {
 func (e *Event) Index() uint64 {
 	return e.Node.ModifiedIndex
 }
+
+func (e *Event) Clone() *Event {
+	return &Event{
+		Action:    e.Action,
+		EtcdIndex: e.EtcdIndex,
+		Node:      e.Node.Clone(),
+		PrevNode:  e.PrevNode.Clone(),
+	}
+}

+ 31 - 0
store/event_test.go

@@ -100,3 +100,34 @@ func TestFullEventQueue(t *testing.T) {
 		}
 	}
 }
+
+func TestCloneEvent(t *testing.T) {
+	e1 := &Event{
+		Action:    Create,
+		EtcdIndex: 1,
+		Node:      nil,
+		PrevNode:  nil,
+	}
+	e2 := e1.Clone()
+	if e2.Action != Create {
+		t.Fatalf("Action=%q, want %q", e2.Action, Create)
+	}
+	if e2.EtcdIndex != e1.EtcdIndex {
+		t.Fatalf("EtcdIndex=%d, want %d", e2.EtcdIndex, e1.EtcdIndex)
+	}
+	// Changing the cloned node should not affect the original
+	e2.Action = Delete
+	e2.EtcdIndex = uint64(5)
+	if e1.Action != Create {
+		t.Fatalf("Action=%q, want %q", e1.Action, Create)
+	}
+	if e1.EtcdIndex != uint64(1) {
+		t.Fatalf("EtcdIndex=%d, want %d", e1.EtcdIndex, uint64(1))
+	}
+	if e2.Action != Delete {
+		t.Fatalf("Action=%q, want %q", e2.Action, Delete)
+	}
+	if e2.EtcdIndex != uint64(5) {
+		t.Fatalf("EtcdIndex=%d, want %d", e2.EtcdIndex, uint64(5))
+	}
+}

+ 26 - 0
store/node_extern.go

@@ -73,6 +73,32 @@ func (eNode *NodeExtern) loadInternalNode(n *node, recursive, sorted bool, clock
 	eNode.Expiration, eNode.TTL = n.expirationAndTTL(clock)
 }
 
+func (eNode *NodeExtern) Clone() *NodeExtern {
+	if eNode == nil {
+		return nil
+	}
+	en := &NodeExtern{
+		Key:           eNode.Key,
+		Dir:           eNode.Dir,
+		TTL:           eNode.TTL,
+		ModifiedIndex: eNode.ModifiedIndex,
+		CreatedIndex:  eNode.CreatedIndex,
+	}
+	if eNode.Value != nil {
+		s := *eNode.Value
+		en.Value = &s
+	}
+	if eNode.Expiration != nil {
+		t := *eNode.Expiration
+		en.Expiration = &t
+	}
+	eNode.Nodes = make(NodeExterns, len(en.Nodes))
+	for i, n := range en.Nodes {
+		eNode.Nodes[i] = n.Clone()
+	}
+	return en
+}
+
 type NodeExterns []*NodeExtern
 
 // interfaces for sorting

+ 71 - 0
store/node_extern_test.go

@@ -0,0 +1,71 @@
+package store
+
+import (
+	"testing"
+	"time"
+)
+import "github.com/coreos/etcd/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+
+func TestNodeExternClone(t *testing.T) {
+	var eNode *NodeExtern
+	if g := eNode.Clone(); g != nil {
+		t.Fatalf("nil.Clone=%v, want nil", g)
+	}
+
+	const (
+		key string = "/foo/bar"
+		ttl int64  = 123456789
+		ci  uint64 = 123
+		mi  uint64 = 321
+	)
+	var (
+		val  = "some_data"
+		valp = &val
+		exp  = time.Unix(12345, 67890)
+		expp = &exp
+	)
+
+	eNode = &NodeExtern{
+		Key:           key,
+		TTL:           ttl,
+		CreatedIndex:  ci,
+		ModifiedIndex: mi,
+		Value:         valp,
+		Expiration:    expp,
+	}
+
+	gNode := eNode.Clone()
+	// Check the clone is as expected
+	assert.Equal(t, gNode.Key, key)
+	assert.Equal(t, gNode.TTL, ttl)
+	assert.Equal(t, gNode.CreatedIndex, ci)
+	assert.Equal(t, gNode.ModifiedIndex, mi)
+	// values should be the same
+	assert.Equal(t, *gNode.Value, val)
+	assert.Equal(t, *gNode.Expiration, exp)
+	// but pointers should differ
+	if gNode.Value == eNode.Value {
+		t.Fatalf("expected value pointers to differ, but got same!")
+	}
+	if gNode.Expiration == eNode.Expiration {
+		t.Fatalf("expected expiration pointers to differ, but got same!")
+	}
+	// Original should be the same
+	assert.Equal(t, eNode.Key, key)
+	assert.Equal(t, eNode.TTL, ttl)
+	assert.Equal(t, eNode.CreatedIndex, ci)
+	assert.Equal(t, eNode.ModifiedIndex, mi)
+	assert.Equal(t, eNode.Value, valp)
+	assert.Equal(t, eNode.Expiration, expp)
+	// Change the clone and ensure the original is not affected
+	gNode.Key = "/baz"
+	gNode.TTL = 0
+	assert.Equal(t, eNode.Key, key)
+	assert.Equal(t, eNode.TTL, ttl)
+	assert.Equal(t, eNode.CreatedIndex, ci)
+	assert.Equal(t, eNode.ModifiedIndex, mi)
+	// Change the original and ensure the clone is not affected
+	eNode.Key = "/wuf"
+	assert.Equal(t, eNode.Key, "/wuf")
+	assert.Equal(t, gNode.Key, "/baz")
+}