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  }