datasource/etcd/util/versionrule.go (154 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package util import ( "sort" "strings" "github.com/apache/servicecomb-service-center/datasource/etcd/state/kvstore" "github.com/apache/servicecomb-service-center/pkg/util" "github.com/apache/servicecomb-service-center/pkg/validate" ) type VersionRule func(sorted []string, kvs []*kvstore.KeyValue, start, end string) []string func Sort(kvs []*kvstore.KeyValue, cmp func(start, end string) bool) { sorter := newSorter(kvs, cmp, true) sort.Sort(sorter) } func newSorter(kvs []*kvstore.KeyValue, cmp func(start string, end string) bool, ref bool) *serviceKeySorter { tmp := kvs if !ref { tmp = make([]*kvstore.KeyValue, len(kvs)) } sorter := &serviceKeySorter{ sortArr: make([]string, len(kvs)), kvs: tmp, cmp: cmp, } for i, kv := range kvs { key := util.BytesToStringWithNoCopy(kv.Key) ver := key[strings.LastIndex(key, "/")+1:] sorter.sortArr[i] = ver sorter.kvs[i] = kv } return sorter } func (vr VersionRule) Match(kvs []*kvstore.KeyValue, ops ...string) []string { sorter := newSorter(kvs, Larger, false) sort.Sort(sorter) args := [2]string{} switch { case len(ops) > 1: args[1] = ops[1] fallthrough case len(ops) > 0: args[0] = ops[0] } return vr(sorter.sortArr, sorter.kvs, args[0], args[1]) } type serviceKeySorter struct { sortArr []string kvs []*kvstore.KeyValue cmp func(i, j string) bool } func (sks *serviceKeySorter) Len() int { return len(sks.sortArr) } func (sks *serviceKeySorter) Swap(i, j int) { sks.sortArr[i], sks.sortArr[j] = sks.sortArr[j], sks.sortArr[i] sks.kvs[i], sks.kvs[j] = sks.kvs[j], sks.kvs[i] } func (sks *serviceKeySorter) Less(i, j int) bool { return sks.cmp(sks.sortArr[i], sks.sortArr[j]) } func Larger(start, end string) bool { s, _ := validate.VersionToInt64(start) e, _ := validate.VersionToInt64(end) return s > e } func LessEqual(start, end string) bool { return !Larger(start, end) } // Latest return latest version kv func Latest(sorted []string, kvs []*kvstore.KeyValue, _, _ string) []string { if len(sorted) == 0 { return []string{} } return []string{kvs[0].Value.(string)} } // Range return start <= version < end func Range(sorted []string, kvs []*kvstore.KeyValue, start, end string) []string { total := len(sorted) if total == 0 { return []string{} } result := make([]string, 0, total) firstFound := false if Larger(start, end) { start, end = end, start } eldest, latest := sorted[total-1], sorted[0] if Larger(start, latest) || LessEqual(end, eldest) { return []string{} } for i, k := range sorted { if !firstFound { if LessEqual(end, k) { continue } firstFound = true } else if Larger(start, k) { break } // end >= k >= start result = append(result, kvs[i].Value.(string)) } return result } // AtLess return version >= start func AtLess(sorted []string, kvs []*kvstore.KeyValue, start, _ string) []string { total := len(sorted) if total == 0 { return []string{} } result := make([]string, 0, total) if Larger(start, sorted[0]) { return []string{} } for i, k := range sorted { if Larger(start, k) { return result[:i] } result = append(result, kvs[i].Value.(string)) } return result } func ParseVersionRule(versionRule string) func(kvs []*kvstore.KeyValue) []string { if len(versionRule) == 0 { return nil } rangeIdx := strings.Index(versionRule, "-") switch { case versionRule == "latest": return func(kvs []*kvstore.KeyValue) []string { return VersionRule(Latest).Match(kvs) } case versionRule[len(versionRule)-1:] == "+": // 取最低版本及高版本集合 start := versionRule[:len(versionRule)-1] return func(kvs []*kvstore.KeyValue) []string { return VersionRule(AtLess).Match(kvs, start) } case rangeIdx > 0: // 取版本范围集合 start := versionRule[:rangeIdx] end := versionRule[rangeIdx+1:] return func(kvs []*kvstore.KeyValue) []string { return VersionRule(Range).Match(kvs, start, end) } default: // 精确匹配 return nil } } func VersionMatchRule(version string, versionRule string) bool { match := ParseVersionRule(versionRule) if match == nil { return version == versionRule } return len(match([]*kvstore.KeyValue{ { Key: util.StringToBytesWithNoCopy("/" + version), Value: "", }, })) > 0 }