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.
This commit is contained in:
Yicheng Qin
2014-11-05 16:40:15 -08:00
parent fc21f299b1
commit 0c2b45ddc6
4 changed files with 73 additions and 80 deletions

View File

@@ -327,7 +327,8 @@ func (c *Cluster) ValidateConfigurationChange(cc raftpb.ConfChange) error {
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.
func (c *Cluster) AddMember(m *Member) {
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 {
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
}
@@ -390,20 +383,26 @@ func (c *Cluster) UpdateMember(nm *Member) {
// the child nodes of the given node should be sorted by key.
func nodeToMember(n *store.NodeExtern) (*Member, error) {
m := &Member{ID: mustParseMemberIDFromKey(n.Key)}
if len(n.Nodes) != 2 {
return m, fmt.Errorf("len(nodes) = %d, want 2", len(n.Nodes))
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, attributesSuffix); n.Nodes[0].Key != w {
return m, fmt.Errorf("key = %v, want %v", n.Nodes[0].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[0].Value), &m.Attributes); err != nil {
return m, fmt.Errorf("unmarshal attributes error: %v", err)
}
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 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
}

View File

@@ -82,20 +82,21 @@ func TestClusterFromStore(t *testing.T) {
mems []*Member
}{
{
[]*Member{newTestMember(1, nil, "node1", nil)},
[]*Member{newTestMember(1, nil, "", nil)},
},
{
nil,
},
{
[]*Member{
newTestMember(1, nil, "node1", nil),
newTestMember(2, nil, "node2", nil),
newTestMember(1, nil, "", nil),
newTestMember(2, nil, "", nil),
},
},
}
for i, tt := range tests {
hc := newTestCluster(nil)
hc.SetStore(store.New())
for _, m := range tt.mems {
hc.AddMember(m)
}
@@ -500,22 +501,22 @@ func TestNodeToMemberBad(t *testing.T) {
{Key: "/1234/strange"},
}},
{Key: "/1234", Nodes: []*store.NodeExtern{
{Key: "/1234/dynamic", Value: stringp("garbage")},
{Key: "/1234/raftAttributes", Value: stringp("garbage")},
}},
{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/dynamic", Value: stringp(`{"peerURLs":null}`)},
{Key: "/1234/raftAttributes", Value: stringp(`{"peerURLs":null}`)},
{Key: "/1234/strange"},
}},
{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/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"},
}},
}
@@ -543,16 +544,6 @@ func TestClusterAddMember(t *testing.T) {
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) {
t.Errorf("actions = %v, want %v", g, wactions)
@@ -656,9 +647,8 @@ func TestNodeToMember(t *testing.T) {
func newTestCluster(membs []*Member) *Cluster {
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
}

View File

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

View File

@@ -55,19 +55,19 @@ func TestV2Set(t *testing.T) {
"/v2/keys/foo/bar",
v,
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",
url.Values{},
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",
url.Values(map[string][]string{"value": {""}}),
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",
url.Values(map[string][]string{"value": {"YYY"}, "prevIndex": {"4"}}),
url.Values(map[string][]string{"value": {"YYY"}, "prevIndex": {"3"}}),
http.StatusOK,
map[string]interface{}{
"node": map[string]interface{}{
"value": "YYY",
"modifiedIndex": float64(5),
"modifiedIndex": float64(4),
},
"action": "compareAndSwap",
},
@@ -233,8 +233,8 @@ func TestV2CAS(t *testing.T) {
map[string]interface{}{
"errorCode": float64(101),
"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{}{
"errorCode": float64(101),
"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{}{
"errorCode": float64(101),
"message": "Compare failed",
"cause": "[100 != 6]",
"cause": "[100 != 5]",
},
},
{
"/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,
map[string]interface{}{
"errorCode": float64(101),
@@ -448,7 +448,7 @@ func TestV2CAD(t *testing.T) {
map[string]interface{}{
"errorCode": float64(101),
"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,
map[string]interface{}{
"node": map[string]interface{}{
"key": "/foo",
"modifiedIndex": float64(6),
"modifiedIndex": float64(5),
},
"action": "compareAndDelete",
},
@@ -493,7 +493,7 @@ func TestV2CAD(t *testing.T) {
map[string]interface{}{
"node": map[string]interface{}{
"key": "/foovalue",
"modifiedIndex": float64(7),
"modifiedIndex": float64(6),
},
"action": "compareAndDelete",
},
@@ -531,7 +531,7 @@ func TestV2Unique(t *testing.T) {
http.StatusCreated,
map[string]interface{}{
"node": map[string]interface{}{
"key": "/foo/4",
"key": "/foo/3",
"value": "XXX",
},
"action": "create",
@@ -543,7 +543,7 @@ func TestV2Unique(t *testing.T) {
http.StatusCreated,
map[string]interface{}{
"node": map[string]interface{}{
"key": "/foo/5",
"key": "/foo/4",
"value": "XXX",
},
"action": "create",
@@ -555,7 +555,7 @@ func TestV2Unique(t *testing.T) {
http.StatusCreated,
map[string]interface{}{
"node": map[string]interface{}{
"key": "/bar/6",
"key": "/bar/5",
"value": "XXX",
},
"action": "create",
@@ -617,8 +617,8 @@ func TestV2Get(t *testing.T) {
map[string]interface{}{
"key": "/foo/bar",
"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{}{
"key": "/foo/bar",
"dir": true,
"createdIndex": float64(4),
"modifiedIndex": float64(4),
"createdIndex": float64(3),
"modifiedIndex": float64(3),
"nodes": []interface{}{
map[string]interface{}{
"key": "/foo/bar/zar",
"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{}{
"key": "/foo/bar",
"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{}{
"key": "/foo/bar",
"dir": true,
"createdIndex": float64(4),
"modifiedIndex": float64(4),
"createdIndex": float64(3),
"modifiedIndex": float64(3),
"nodes": []interface{}{
map[string]interface{}{
"key": "/foo/bar/zar",
"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{}{
"key": "/foo/bar",
"value": "XXX",
"modifiedIndex": float64(4),
"modifiedIndex": float64(3),
},
"action": "set",
}
@@ -818,7 +818,7 @@ func TestV2WatchWithIndex(t *testing.T) {
var body map[string]interface{}
c := make(chan bool, 1)
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)
c <- true
}()
@@ -855,7 +855,7 @@ func TestV2WatchWithIndex(t *testing.T) {
"node": map[string]interface{}{
"key": "/foo/bar",
"value": "XXX",
"modifiedIndex": float64(5),
"modifiedIndex": float64(4),
},
"action": "set",
}