Browse Source

etcdserver: not record attributes when add member

There is no need to set attributes value when adding member because new
member will publish the information whenever it starts.
Yicheng Qin 11 years ago
parent
commit
0c2b45ddc6
4 changed files with 73 additions and 80 deletions
  1. 20 21
      etcdserver/cluster.go
  2. 13 23
      etcdserver/cluster_test.go
  3. 8 4
      etcdserver/server_test.go
  4. 32 32
      integration/v2_http_kv_test.go

+ 20 - 21
etcdserver/cluster.go

@@ -327,7 +327,8 @@ func (c *Cluster) ValidateConfigurationChange(cc raftpb.ConfChange) error {
 	return nil
 	return nil
 }
 }
 
 
-// AddMember puts a new Member into the store.
+// AddMember adds a new Member into the cluster, and saves the given member's
+// raftAttributes into the store. The given member should have empty attributes.
 // A Member with a matching id must not exist.
 // A Member with a matching id must not exist.
 func (c *Cluster) AddMember(m *Member) {
 func (c *Cluster) AddMember(m *Member) {
 	c.Lock()
 	c.Lock()
@@ -340,14 +341,6 @@ func (c *Cluster) AddMember(m *Member) {
 	if _, err := c.store.Create(p, false, string(b), false, store.Permanent); err != nil {
 	if _, err := c.store.Create(p, false, string(b), false, store.Permanent); err != nil {
 		log.Panicf("create raftAttributes should never fail: %v", err)
 		log.Panicf("create raftAttributes should never fail: %v", err)
 	}
 	}
-	b, err = json.Marshal(m.Attributes)
-	if err != nil {
-		log.Panicf("marshal attributes should never fail: %v", err)
-	}
-	p = path.Join(memberStoreKey(m.ID), attributesSuffix)
-	if _, err := c.store.Create(p, false, string(b), false, store.Permanent); err != nil {
-		log.Panicf("create attributes should never fail: %v", err)
-	}
 	c.members[m.ID] = m
 	c.members[m.ID] = m
 }
 }
 
 
@@ -390,20 +383,26 @@ func (c *Cluster) UpdateMember(nm *Member) {
 // the child nodes of the given node should be sorted by key.
 // the child nodes of the given node should be sorted by key.
 func nodeToMember(n *store.NodeExtern) (*Member, error) {
 func nodeToMember(n *store.NodeExtern) (*Member, error) {
 	m := &Member{ID: mustParseMemberIDFromKey(n.Key)}
 	m := &Member{ID: mustParseMemberIDFromKey(n.Key)}
-	if len(n.Nodes) != 2 {
-		return m, fmt.Errorf("len(nodes) = %d, want 2", len(n.Nodes))
-	}
-	if w := path.Join(n.Key, attributesSuffix); n.Nodes[0].Key != w {
-		return m, fmt.Errorf("key = %v, want %v", n.Nodes[0].Key, w)
-	}
-	if err := json.Unmarshal([]byte(*n.Nodes[0].Value), &m.Attributes); err != nil {
-		return m, fmt.Errorf("unmarshal attributes error: %v", err)
+	attrs := make(map[string][]byte)
+	raftAttrKey := path.Join(n.Key, raftAttributesSuffix)
+	attrKey := path.Join(n.Key, attributesSuffix)
+	for _, nn := range n.Nodes {
+		if nn.Key != raftAttrKey && nn.Key != attrKey {
+			return nil, fmt.Errorf("unknown key %q", nn.Key)
+		}
+		attrs[nn.Key] = []byte(*nn.Value)
 	}
 	}
-	if w := path.Join(n.Key, raftAttributesSuffix); n.Nodes[1].Key != w {
-		return m, fmt.Errorf("key = %v, want %v", n.Nodes[1].Key, w)
+	if data := attrs[raftAttrKey]; data != nil {
+		if err := json.Unmarshal(data, &m.RaftAttributes); err != nil {
+			return nil, fmt.Errorf("unmarshal raftAttributes error: %v", err)
+		}
+	} else {
+		return nil, fmt.Errorf("raftAttributes key doesn't exist")
 	}
 	}
-	if err := json.Unmarshal([]byte(*n.Nodes[1].Value), &m.RaftAttributes); err != nil {
-		return m, fmt.Errorf("unmarshal raftAttributes error: %v", err)
+	if data := attrs[attrKey]; data != nil {
+		if err := json.Unmarshal(data, &m.Attributes); err != nil {
+			return m, fmt.Errorf("unmarshal attributes error: %v", err)
+		}
 	}
 	}
 	return m, nil
 	return m, nil
 }
 }

+ 13 - 23
etcdserver/cluster_test.go

@@ -82,20 +82,21 @@ func TestClusterFromStore(t *testing.T) {
 		mems []*Member
 		mems []*Member
 	}{
 	}{
 		{
 		{
-			[]*Member{newTestMember(1, nil, "node1", nil)},
+			[]*Member{newTestMember(1, nil, "", nil)},
 		},
 		},
 		{
 		{
 			nil,
 			nil,
 		},
 		},
 		{
 		{
 			[]*Member{
 			[]*Member{
-				newTestMember(1, nil, "node1", nil),
-				newTestMember(2, nil, "node2", nil),
+				newTestMember(1, nil, "", nil),
+				newTestMember(2, nil, "", nil),
 			},
 			},
 		},
 		},
 	}
 	}
 	for i, tt := range tests {
 	for i, tt := range tests {
 		hc := newTestCluster(nil)
 		hc := newTestCluster(nil)
+		hc.SetStore(store.New())
 		for _, m := range tt.mems {
 		for _, m := range tt.mems {
 			hc.AddMember(m)
 			hc.AddMember(m)
 		}
 		}
@@ -500,22 +501,22 @@ func TestNodeToMemberBad(t *testing.T) {
 			{Key: "/1234/strange"},
 			{Key: "/1234/strange"},
 		}},
 		}},
 		{Key: "/1234", Nodes: []*store.NodeExtern{
 		{Key: "/1234", Nodes: []*store.NodeExtern{
-			{Key: "/1234/dynamic", Value: stringp("garbage")},
+			{Key: "/1234/raftAttributes", Value: stringp("garbage")},
 		}},
 		}},
 		{Key: "/1234", Nodes: []*store.NodeExtern{
 		{Key: "/1234", Nodes: []*store.NodeExtern{
-			{Key: "/1234/dynamic", Value: stringp(`{"peerURLs":null}`)},
+			{Key: "/1234/attributes", Value: stringp(`{"name":"node1","clientURLs":null}`)},
 		}},
 		}},
 		{Key: "/1234", Nodes: []*store.NodeExtern{
 		{Key: "/1234", Nodes: []*store.NodeExtern{
-			{Key: "/1234/dynamic", Value: stringp(`{"peerURLs":null}`)},
+			{Key: "/1234/raftAttributes", Value: stringp(`{"peerURLs":null}`)},
 			{Key: "/1234/strange"},
 			{Key: "/1234/strange"},
 		}},
 		}},
 		{Key: "/1234", Nodes: []*store.NodeExtern{
 		{Key: "/1234", Nodes: []*store.NodeExtern{
-			{Key: "/1234/dynamic", Value: stringp(`{"peerURLs":null}`)},
-			{Key: "/1234/static", Value: stringp("garbage")},
+			{Key: "/1234/raftAttributes", Value: stringp(`{"peerURLs":null}`)},
+			{Key: "/1234/attributes", Value: stringp("garbage")},
 		}},
 		}},
 		{Key: "/1234", Nodes: []*store.NodeExtern{
 		{Key: "/1234", Nodes: []*store.NodeExtern{
-			{Key: "/1234/dynamic", Value: stringp(`{"peerURLs":null}`)},
-			{Key: "/1234/static", Value: stringp(`{"name":"node1","clientURLs":null}`)},
+			{Key: "/1234/raftAttributes", Value: stringp(`{"peerURLs":null}`)},
+			{Key: "/1234/attributes", Value: stringp(`{"name":"node1","clientURLs":null}`)},
 			{Key: "/1234/strange"},
 			{Key: "/1234/strange"},
 		}},
 		}},
 	}
 	}
@@ -543,16 +544,6 @@ func TestClusterAddMember(t *testing.T) {
 				store.Permanent,
 				store.Permanent,
 			},
 			},
 		},
 		},
-		{
-			name: "Create",
-			params: []interface{}{
-				path.Join(storeMembersPrefix, "1", "attributes"),
-				false,
-				`{"name":"node1"}`,
-				false,
-				store.Permanent,
-			},
-		},
 	}
 	}
 	if g := st.Action(); !reflect.DeepEqual(g, wactions) {
 	if g := st.Action(); !reflect.DeepEqual(g, wactions) {
 		t.Errorf("actions = %v, want %v", g, wactions)
 		t.Errorf("actions = %v, want %v", g, wactions)
@@ -656,9 +647,8 @@ func TestNodeToMember(t *testing.T) {
 
 
 func newTestCluster(membs []*Member) *Cluster {
 func newTestCluster(membs []*Member) *Cluster {
 	c := &Cluster{members: make(map[types.ID]*Member), removed: make(map[types.ID]bool)}
 	c := &Cluster{members: make(map[types.ID]*Member), removed: make(map[types.ID]bool)}
-	c.store = store.New()
-	for i := range membs {
-		c.AddMember(membs[i])
+	for _, m := range membs {
+		c.members[m.ID] = m
 	}
 	}
 	return c
 	return c
 }
 }

+ 8 - 4
etcdserver/server_test.go

@@ -554,8 +554,8 @@ func testServer(t *testing.T, ns uint64) {
 
 
 		g, w := resp.Event.Node, &store.NodeExtern{
 		g, w := resp.Event.Node, &store.NodeExtern{
 			Key:           "/foo",
 			Key:           "/foo",
-			ModifiedIndex: uint64(i) + 2*ns,
-			CreatedIndex:  uint64(i) + 2*ns,
+			ModifiedIndex: uint64(i) + ns,
+			CreatedIndex:  uint64(i) + ns,
 			Value:         stringp("bar"),
 			Value:         stringp("bar"),
 		}
 		}
 
 
@@ -993,7 +993,9 @@ func TestRemoveMember(t *testing.T) {
 			Nodes:     []uint64{1234, 2345, 3456},
 			Nodes:     []uint64{1234, 2345, 3456},
 		},
 		},
 	}
 	}
-	cl := newTestCluster([]*Member{{ID: 1234}})
+	cl := newTestCluster(nil)
+	cl.SetStore(store.New())
+	cl.AddMember(&Member{ID: 1234})
 	s := &EtcdServer{
 	s := &EtcdServer{
 		node:    n,
 		node:    n,
 		store:   &storeRecorder{},
 		store:   &storeRecorder{},
@@ -1027,7 +1029,9 @@ func TestUpdateMember(t *testing.T) {
 			Nodes:     []uint64{1234, 2345, 3456},
 			Nodes:     []uint64{1234, 2345, 3456},
 		},
 		},
 	}
 	}
-	cl := newTestCluster([]*Member{{ID: 1234}})
+	cl := newTestCluster(nil)
+	cl.SetStore(store.New())
+	cl.AddMember(&Member{ID: 1234})
 	s := &EtcdServer{
 	s := &EtcdServer{
 		node:    n,
 		node:    n,
 		store:   &storeRecorder{},
 		store:   &storeRecorder{},

+ 32 - 32
integration/v2_http_kv_test.go

@@ -55,19 +55,19 @@ func TestV2Set(t *testing.T) {
 			"/v2/keys/foo/bar",
 			"/v2/keys/foo/bar",
 			v,
 			v,
 			http.StatusCreated,
 			http.StatusCreated,
-			`{"action":"set","node":{"key":"/foo/bar","value":"bar","modifiedIndex":4,"createdIndex":4}}`,
+			`{"action":"set","node":{"key":"/foo/bar","value":"bar","modifiedIndex":3,"createdIndex":3}}`,
 		},
 		},
 		{
 		{
 			"/v2/keys/foodir?dir=true",
 			"/v2/keys/foodir?dir=true",
 			url.Values{},
 			url.Values{},
 			http.StatusCreated,
 			http.StatusCreated,
-			`{"action":"set","node":{"key":"/foodir","dir":true,"modifiedIndex":5,"createdIndex":5}}`,
+			`{"action":"set","node":{"key":"/foodir","dir":true,"modifiedIndex":4,"createdIndex":4}}`,
 		},
 		},
 		{
 		{
 			"/v2/keys/fooempty",
 			"/v2/keys/fooempty",
 			url.Values(map[string][]string{"value": {""}}),
 			url.Values(map[string][]string{"value": {""}}),
 			http.StatusCreated,
 			http.StatusCreated,
-			`{"action":"set","node":{"key":"/fooempty","value":"","modifiedIndex":6,"createdIndex":6}}`,
+			`{"action":"set","node":{"key":"/fooempty","value":"","modifiedIndex":5,"createdIndex":5}}`,
 		},
 		},
 	}
 	}
 
 
@@ -216,12 +216,12 @@ func TestV2CAS(t *testing.T) {
 		},
 		},
 		{
 		{
 			"/v2/keys/cas/foo",
 			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"YYY"}, "prevIndex": {"4"}}),
+			url.Values(map[string][]string{"value": {"YYY"}, "prevIndex": {"3"}}),
 			http.StatusOK,
 			http.StatusOK,
 			map[string]interface{}{
 			map[string]interface{}{
 				"node": map[string]interface{}{
 				"node": map[string]interface{}{
 					"value":         "YYY",
 					"value":         "YYY",
-					"modifiedIndex": float64(5),
+					"modifiedIndex": float64(4),
 				},
 				},
 				"action": "compareAndSwap",
 				"action": "compareAndSwap",
 			},
 			},
@@ -233,8 +233,8 @@ func TestV2CAS(t *testing.T) {
 			map[string]interface{}{
 			map[string]interface{}{
 				"errorCode": float64(101),
 				"errorCode": float64(101),
 				"message":   "Compare failed",
 				"message":   "Compare failed",
-				"cause":     "[10 != 5]",
-				"index":     float64(5),
+				"cause":     "[10 != 4]",
+				"index":     float64(4),
 			},
 			},
 		},
 		},
 		{
 		{
@@ -283,7 +283,7 @@ func TestV2CAS(t *testing.T) {
 			map[string]interface{}{
 			map[string]interface{}{
 				"errorCode": float64(101),
 				"errorCode": float64(101),
 				"message":   "Compare failed",
 				"message":   "Compare failed",
-				"cause":     "[bad_value != ZZZ] [100 != 6]",
+				"cause":     "[bad_value != ZZZ] [100 != 5]",
 			},
 			},
 		},
 		},
 		{
 		{
@@ -293,12 +293,12 @@ func TestV2CAS(t *testing.T) {
 			map[string]interface{}{
 			map[string]interface{}{
 				"errorCode": float64(101),
 				"errorCode": float64(101),
 				"message":   "Compare failed",
 				"message":   "Compare failed",
-				"cause":     "[100 != 6]",
+				"cause":     "[100 != 5]",
 			},
 			},
 		},
 		},
 		{
 		{
 			"/v2/keys/cas/foo",
 			"/v2/keys/cas/foo",
-			url.Values(map[string][]string{"value": {"XXX"}, "prevValue": {"bad_value"}, "prevIndex": {"6"}}),
+			url.Values(map[string][]string{"value": {"XXX"}, "prevValue": {"bad_value"}, "prevIndex": {"5"}}),
 			http.StatusPreconditionFailed,
 			http.StatusPreconditionFailed,
 			map[string]interface{}{
 			map[string]interface{}{
 				"errorCode": float64(101),
 				"errorCode": float64(101),
@@ -448,7 +448,7 @@ func TestV2CAD(t *testing.T) {
 			map[string]interface{}{
 			map[string]interface{}{
 				"errorCode": float64(101),
 				"errorCode": float64(101),
 				"message":   "Compare failed",
 				"message":   "Compare failed",
-				"cause":     "[100 != 4]",
+				"cause":     "[100 != 3]",
 			},
 			},
 		},
 		},
 		{
 		{
@@ -460,12 +460,12 @@ func TestV2CAD(t *testing.T) {
 			},
 			},
 		},
 		},
 		{
 		{
-			"/v2/keys/foo?prevIndex=4",
+			"/v2/keys/foo?prevIndex=3",
 			http.StatusOK,
 			http.StatusOK,
 			map[string]interface{}{
 			map[string]interface{}{
 				"node": map[string]interface{}{
 				"node": map[string]interface{}{
 					"key":           "/foo",
 					"key":           "/foo",
-					"modifiedIndex": float64(6),
+					"modifiedIndex": float64(5),
 				},
 				},
 				"action": "compareAndDelete",
 				"action": "compareAndDelete",
 			},
 			},
@@ -493,7 +493,7 @@ func TestV2CAD(t *testing.T) {
 			map[string]interface{}{
 			map[string]interface{}{
 				"node": map[string]interface{}{
 				"node": map[string]interface{}{
 					"key":           "/foovalue",
 					"key":           "/foovalue",
-					"modifiedIndex": float64(7),
+					"modifiedIndex": float64(6),
 				},
 				},
 				"action": "compareAndDelete",
 				"action": "compareAndDelete",
 			},
 			},
@@ -531,7 +531,7 @@ func TestV2Unique(t *testing.T) {
 			http.StatusCreated,
 			http.StatusCreated,
 			map[string]interface{}{
 			map[string]interface{}{
 				"node": map[string]interface{}{
 				"node": map[string]interface{}{
-					"key":   "/foo/4",
+					"key":   "/foo/3",
 					"value": "XXX",
 					"value": "XXX",
 				},
 				},
 				"action": "create",
 				"action": "create",
@@ -543,7 +543,7 @@ func TestV2Unique(t *testing.T) {
 			http.StatusCreated,
 			http.StatusCreated,
 			map[string]interface{}{
 			map[string]interface{}{
 				"node": map[string]interface{}{
 				"node": map[string]interface{}{
-					"key":   "/foo/5",
+					"key":   "/foo/4",
 					"value": "XXX",
 					"value": "XXX",
 				},
 				},
 				"action": "create",
 				"action": "create",
@@ -555,7 +555,7 @@ func TestV2Unique(t *testing.T) {
 			http.StatusCreated,
 			http.StatusCreated,
 			map[string]interface{}{
 			map[string]interface{}{
 				"node": map[string]interface{}{
 				"node": map[string]interface{}{
-					"key":   "/bar/6",
+					"key":   "/bar/5",
 					"value": "XXX",
 					"value": "XXX",
 				},
 				},
 				"action": "create",
 				"action": "create",
@@ -617,8 +617,8 @@ func TestV2Get(t *testing.T) {
 						map[string]interface{}{
 						map[string]interface{}{
 							"key":           "/foo/bar",
 							"key":           "/foo/bar",
 							"dir":           true,
 							"dir":           true,
-							"createdIndex":  float64(4),
-							"modifiedIndex": float64(4),
+							"createdIndex":  float64(3),
+							"modifiedIndex": float64(3),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -636,14 +636,14 @@ func TestV2Get(t *testing.T) {
 						map[string]interface{}{
 						map[string]interface{}{
 							"key":           "/foo/bar",
 							"key":           "/foo/bar",
 							"dir":           true,
 							"dir":           true,
-							"createdIndex":  float64(4),
-							"modifiedIndex": float64(4),
+							"createdIndex":  float64(3),
+							"modifiedIndex": float64(3),
 							"nodes": []interface{}{
 							"nodes": []interface{}{
 								map[string]interface{}{
 								map[string]interface{}{
 									"key":           "/foo/bar/zar",
 									"key":           "/foo/bar/zar",
 									"value":         "XXX",
 									"value":         "XXX",
-									"createdIndex":  float64(4),
-									"modifiedIndex": float64(4),
+									"createdIndex":  float64(3),
+									"modifiedIndex": float64(3),
 								},
 								},
 							},
 							},
 						},
 						},
@@ -711,8 +711,8 @@ func TestV2QuorumGet(t *testing.T) {
 						map[string]interface{}{
 						map[string]interface{}{
 							"key":           "/foo/bar",
 							"key":           "/foo/bar",
 							"dir":           true,
 							"dir":           true,
-							"createdIndex":  float64(4),
-							"modifiedIndex": float64(4),
+							"createdIndex":  float64(3),
+							"modifiedIndex": float64(3),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -730,14 +730,14 @@ func TestV2QuorumGet(t *testing.T) {
 						map[string]interface{}{
 						map[string]interface{}{
 							"key":           "/foo/bar",
 							"key":           "/foo/bar",
 							"dir":           true,
 							"dir":           true,
-							"createdIndex":  float64(4),
-							"modifiedIndex": float64(4),
+							"createdIndex":  float64(3),
+							"modifiedIndex": float64(3),
 							"nodes": []interface{}{
 							"nodes": []interface{}{
 								map[string]interface{}{
 								map[string]interface{}{
 									"key":           "/foo/bar/zar",
 									"key":           "/foo/bar/zar",
 									"value":         "XXX",
 									"value":         "XXX",
-									"createdIndex":  float64(4),
-									"modifiedIndex": float64(4),
+									"createdIndex":  float64(3),
+									"modifiedIndex": float64(3),
 								},
 								},
 							},
 							},
 						},
 						},
@@ -797,7 +797,7 @@ func TestV2Watch(t *testing.T) {
 		"node": map[string]interface{}{
 		"node": map[string]interface{}{
 			"key":           "/foo/bar",
 			"key":           "/foo/bar",
 			"value":         "XXX",
 			"value":         "XXX",
-			"modifiedIndex": float64(4),
+			"modifiedIndex": float64(3),
 		},
 		},
 		"action": "set",
 		"action": "set",
 	}
 	}
@@ -818,7 +818,7 @@ func TestV2WatchWithIndex(t *testing.T) {
 	var body map[string]interface{}
 	var body map[string]interface{}
 	c := make(chan bool, 1)
 	c := make(chan bool, 1)
 	go func() {
 	go func() {
-		resp, _ := tc.Get(fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar?wait=true&waitIndex=5"))
+		resp, _ := tc.Get(fmt.Sprintf("%s%s", u, "/v2/keys/foo/bar?wait=true&waitIndex=4"))
 		body = tc.ReadBodyJSON(resp)
 		body = tc.ReadBodyJSON(resp)
 		c <- true
 		c <- true
 	}()
 	}()
@@ -855,7 +855,7 @@ func TestV2WatchWithIndex(t *testing.T) {
 		"node": map[string]interface{}{
 		"node": map[string]interface{}{
 			"key":           "/foo/bar",
 			"key":           "/foo/bar",
 			"value":         "XXX",
 			"value":         "XXX",
-			"modifiedIndex": float64(5),
+			"modifiedIndex": float64(4),
 		},
 		},
 		"action": "set",
 		"action": "set",
 	}
 	}