go.etcd.io/etcd@v3.3.27+incompatible/etcdserver/membership/store.go (about) 1 // Copyright 2016 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package membership 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "path" 21 22 "github.com/coreos/etcd/mvcc/backend" 23 "github.com/coreos/etcd/pkg/types" 24 "github.com/coreos/etcd/store" 25 26 "github.com/coreos/go-semver/semver" 27 ) 28 29 const ( 30 attributesSuffix = "attributes" 31 raftAttributesSuffix = "raftAttributes" 32 33 // the prefix for stroing membership related information in store provided by store pkg. 34 storePrefix = "/0" 35 ) 36 37 var ( 38 membersBucketName = []byte("members") 39 membersRemovedBucketName = []byte("members_removed") 40 clusterBucketName = []byte("cluster") 41 42 StoreMembersPrefix = path.Join(storePrefix, "members") 43 storeRemovedMembersPrefix = path.Join(storePrefix, "removed_members") 44 ) 45 46 func mustSaveMemberToBackend(be backend.Backend, m *Member) { 47 mkey := backendMemberKey(m.ID) 48 mvalue, err := json.Marshal(m) 49 if err != nil { 50 plog.Panicf("marshal raftAttributes should never fail: %v", err) 51 } 52 53 tx := be.BatchTx() 54 tx.Lock() 55 tx.UnsafePut(membersBucketName, mkey, mvalue) 56 tx.Unlock() 57 } 58 59 func mustDeleteMemberFromBackend(be backend.Backend, id types.ID) { 60 mkey := backendMemberKey(id) 61 62 tx := be.BatchTx() 63 tx.Lock() 64 tx.UnsafeDelete(membersBucketName, mkey) 65 tx.UnsafePut(membersRemovedBucketName, mkey, []byte("removed")) 66 tx.Unlock() 67 } 68 69 func mustSaveClusterVersionToBackend(be backend.Backend, ver *semver.Version) { 70 ckey := backendClusterVersionKey() 71 72 tx := be.BatchTx() 73 tx.Lock() 74 defer tx.Unlock() 75 tx.UnsafePut(clusterBucketName, ckey, []byte(ver.String())) 76 } 77 78 func mustSaveMemberToStore(s store.Store, m *Member) { 79 b, err := json.Marshal(m.RaftAttributes) 80 if err != nil { 81 plog.Panicf("marshal raftAttributes should never fail: %v", err) 82 } 83 p := path.Join(MemberStoreKey(m.ID), raftAttributesSuffix) 84 if _, err := s.Create(p, false, string(b), false, store.TTLOptionSet{ExpireTime: store.Permanent}); err != nil { 85 plog.Panicf("create raftAttributes should never fail: %v", err) 86 } 87 } 88 89 func mustDeleteMemberFromStore(s store.Store, id types.ID) { 90 if _, err := s.Delete(MemberStoreKey(id), true, true); err != nil { 91 plog.Panicf("delete member should never fail: %v", err) 92 } 93 if _, err := s.Create(RemovedMemberStoreKey(id), false, "", false, store.TTLOptionSet{ExpireTime: store.Permanent}); err != nil { 94 plog.Panicf("create removedMember should never fail: %v", err) 95 } 96 } 97 98 func mustUpdateMemberInStore(s store.Store, m *Member) { 99 b, err := json.Marshal(m.RaftAttributes) 100 if err != nil { 101 plog.Panicf("marshal raftAttributes should never fail: %v", err) 102 } 103 p := path.Join(MemberStoreKey(m.ID), raftAttributesSuffix) 104 if _, err := s.Update(p, string(b), store.TTLOptionSet{ExpireTime: store.Permanent}); err != nil { 105 plog.Panicf("update raftAttributes should never fail: %v", err) 106 } 107 } 108 109 func mustUpdateMemberAttrInStore(s store.Store, m *Member) { 110 b, err := json.Marshal(m.Attributes) 111 if err != nil { 112 plog.Panicf("marshal raftAttributes should never fail: %v", err) 113 } 114 p := path.Join(MemberStoreKey(m.ID), attributesSuffix) 115 if _, err := s.Set(p, false, string(b), store.TTLOptionSet{ExpireTime: store.Permanent}); err != nil { 116 plog.Panicf("update raftAttributes should never fail: %v", err) 117 } 118 } 119 120 func mustSaveClusterVersionToStore(s store.Store, ver *semver.Version) { 121 if _, err := s.Set(StoreClusterVersionKey(), false, ver.String(), store.TTLOptionSet{ExpireTime: store.Permanent}); err != nil { 122 plog.Panicf("save cluster version should never fail: %v", err) 123 } 124 } 125 126 // nodeToMember builds member from a key value node. 127 // the child nodes of the given node MUST be sorted by key. 128 func nodeToMember(n *store.NodeExtern) (*Member, error) { 129 m := &Member{ID: MustParseMemberIDFromKey(n.Key)} 130 attrs := make(map[string][]byte) 131 raftAttrKey := path.Join(n.Key, raftAttributesSuffix) 132 attrKey := path.Join(n.Key, attributesSuffix) 133 for _, nn := range n.Nodes { 134 if nn.Key != raftAttrKey && nn.Key != attrKey { 135 return nil, fmt.Errorf("unknown key %q", nn.Key) 136 } 137 attrs[nn.Key] = []byte(*nn.Value) 138 } 139 if data := attrs[raftAttrKey]; data != nil { 140 if err := json.Unmarshal(data, &m.RaftAttributes); err != nil { 141 return nil, fmt.Errorf("unmarshal raftAttributes error: %v", err) 142 } 143 } else { 144 return nil, fmt.Errorf("raftAttributes key doesn't exist") 145 } 146 if data := attrs[attrKey]; data != nil { 147 if err := json.Unmarshal(data, &m.Attributes); err != nil { 148 return m, fmt.Errorf("unmarshal attributes error: %v", err) 149 } 150 } 151 return m, nil 152 } 153 154 func backendMemberKey(id types.ID) []byte { 155 return []byte(id.String()) 156 } 157 158 func backendClusterVersionKey() []byte { 159 return []byte("clusterVersion") 160 } 161 162 func mustCreateBackendBuckets(be backend.Backend) { 163 tx := be.BatchTx() 164 tx.Lock() 165 defer tx.Unlock() 166 tx.UnsafeCreateBucket(membersBucketName) 167 tx.UnsafeCreateBucket(membersRemovedBucketName) 168 tx.UnsafeCreateBucket(clusterBucketName) 169 } 170 171 func MemberStoreKey(id types.ID) string { 172 return path.Join(StoreMembersPrefix, id.String()) 173 } 174 175 func StoreClusterVersionKey() string { 176 return path.Join(storePrefix, "version") 177 } 178 179 func MemberAttributesStorePath(id types.ID) string { 180 return path.Join(MemberStoreKey(id), attributesSuffix) 181 } 182 183 func MustParseMemberIDFromKey(key string) types.ID { 184 id, err := types.IDFromString(path.Base(key)) 185 if err != nil { 186 plog.Panicf("unexpected parse member id error: %v", err) 187 } 188 return id 189 } 190 191 func RemovedMemberStoreKey(id types.ID) string { 192 return path.Join(storeRemovedMembersPrefix, id.String()) 193 }