func mustSaveClusterVersionToBackend(be backend.Backend, ver *semver.Version) { ckey := backendClusterVersionKey() tx := be.BatchTx() tx.Lock() defer tx.Unlock() tx.UnsafePut(clusterBucketName, ckey, []byte(ver.String())) }
func (c *cluster) SetVersion(ver *semver.Version) { c.Lock() defer c.Unlock() if c.version != nil { plog.Noticef("updated the cluster version from %v to %v", c.version.String(), ver.String()) } else { plog.Noticef("set the initial cluster version to %v", ver.String()) } c.version = ver }
func (c *RaftCluster) SetVersion(ver *semver.Version) { c.Lock() defer c.Unlock() if c.version != nil { plog.Noticef("updated the cluster version from %v to %v", version.Cluster(c.version.String()), version.Cluster(ver.String())) } else { plog.Noticef("set the initial cluster version to %v", version.Cluster(ver.String())) } c.version = ver mustDetectDowngrade(c.version) }
// UpdateCapability updates the enabledMap when the cluster version increases. func UpdateCapability(v *semver.Version) { if v == nil { // if recovered but version was never set by cluster return } enableMapMu.Lock() if curVersion != nil && !curVersion.LessThan(*v) { enableMapMu.Unlock() return } curVersion = v enabledMap = capabilityMaps[curVersion.String()] enableMapMu.Unlock() plog.Infof("enabled capabilities for version %s", version.Cluster(v.String())) }
func (c *RaftCluster) SetVersion(ver *semver.Version, onSet func(*semver.Version)) { c.Lock() defer c.Unlock() if c.version != nil { plog.Noticef("updated the cluster version from %v to %v", version.Cluster(c.version.String()), version.Cluster(ver.String())) } else { plog.Noticef("set the initial cluster version to %v", version.Cluster(ver.String())) } c.version = ver mustDetectDowngrade(c.version) if c.store != nil { mustSaveClusterVersionToStore(c.store, ver) } if c.be != nil { mustSaveClusterVersionToBackend(c.be, ver) } onSet(ver) }
// capabilityLoop checks the cluster version every 500ms and updates // the enabledMap when the cluster version increased. // capabilityLoop MUST be ran in a goroutine before checking capability // or using capabilityHandler. func capabilityLoop(s *etcdserver.EtcdServer) { stopped := s.StopNotify() var pv *semver.Version for { if v := s.ClusterVersion(); v != pv { if pv == nil || (v != nil && pv.LessThan(*v)) { pv = v enableMapMu.Lock() enabledMap = capabilityMaps[pv.String()] enableMapMu.Unlock() plog.Infof("enabled capabilities for version %s", pv) } } select { case <-stopped: return case <-time.After(500 * time.Millisecond): } } }
func mustSaveClusterVersionToStore(s store.Store, ver *semver.Version) { if _, err := s.Set(StoreClusterVersionKey(), false, ver.String(), store.TTLOptionSet{ExpireTime: store.Permanent}); err != nil { plog.Panicf("save cluster version should never fail: %v", err) } }
func MustDetectDowngrade(cv *semver.Version) { lv := semver.Must(semver.NewVersion(version.Version)) // only keep major.minor version for comparison against cluster version lv = &semver.Version{Major: lv.Major, Minor: lv.Minor} if cv != nil && lv.LessThan(*cv) { plog.Fatalf("cluster cannot be downgraded (current version: %s is lower than determined cluster version: %s).", version.Version, version.Cluster(cv.String())) } }
func isCompatibleWithVers(vers map[string]*version.Versions, local types.ID, minV, maxV *semver.Version) bool { var ok bool for id, v := range vers { // ignore comparison with local version if id == local.String() { continue } if v == nil { continue } clusterv, err := semver.NewVersion(v.Cluster) if err != nil { plog.Errorf("cannot understand the cluster version of member %s (%v)", id, err) continue } if clusterv.LessThan(*minV) { plog.Warningf("the running cluster version(%v) is lower than the minimal cluster version(%v) supported", clusterv.String(), minV.String()) return false } if maxV.LessThan(*clusterv) { plog.Warningf("the running cluster version(%v) is higher than the maximum cluster version(%v) supported", clusterv.String(), maxV.String()) return false } ok = true } return ok }