github.com/polarismesh/polaris@v1.17.8/store/boltdb/instance.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package boltdb
    19  
    20  import (
    21  	"errors"
    22  	"fmt"
    23  	"sort"
    24  	"strconv"
    25  	"strings"
    26  	"time"
    27  
    28  	"github.com/golang/protobuf/ptypes/wrappers"
    29  	apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage"
    30  	bolt "go.etcd.io/bbolt"
    31  	"google.golang.org/protobuf/types/known/wrapperspb"
    32  
    33  	"github.com/polarismesh/polaris/common/model"
    34  	commontime "github.com/polarismesh/polaris/common/time"
    35  	"github.com/polarismesh/polaris/common/utils"
    36  	"github.com/polarismesh/polaris/store"
    37  )
    38  
    39  type instanceStore struct {
    40  	handler BoltHandler
    41  }
    42  
    43  const (
    44  	tblNameInstance    = "instance"
    45  	insFieldProto      = "Proto"
    46  	insFieldServiceID  = "ServiceID"
    47  	insFieldModifyTime = "ModifyTime"
    48  	insFieldValid      = "Valid"
    49  )
    50  
    51  // AddInstance add an instance
    52  func (i *instanceStore) AddInstance(instance *model.Instance) error {
    53  	initInstance([]*model.Instance{instance})
    54  	// Before adding new data, you must clean up the old data
    55  	if err := i.handler.DeleteValues(tblNameInstance, []string{instance.ID()}); err != nil {
    56  		log.Errorf("[Store][boltdb] delete instance to kv error, %v", err)
    57  		return err
    58  	}
    59  
    60  	if err := i.handler.SaveValue(tblNameInstance, instance.ID(), instance); err != nil {
    61  		log.Errorf("[Store][boltdb] save instance to kv error, %v", err)
    62  		return err
    63  	}
    64  
    65  	return nil
    66  }
    67  
    68  // BatchAddInstances Add multiple instances
    69  func (i *instanceStore) BatchAddInstances(instances []*model.Instance) error {
    70  
    71  	if len(instances) == 0 {
    72  		return nil
    73  	}
    74  
    75  	var insIds []string
    76  	for _, instance := range instances {
    77  		insIds = append(insIds, instance.ID())
    78  	}
    79  
    80  	// clear old instances
    81  	if err := i.handler.DeleteValues(tblNameInstance, insIds); err != nil {
    82  		log.Errorf("[Store][boltdb] save instance to kv error, %v", err)
    83  		return err
    84  	}
    85  
    86  	initInstance(instances)
    87  	for _, instance := range instances {
    88  		if err := i.handler.SaveValue(tblNameInstance, instance.ID(), instance); err != nil {
    89  			log.Errorf("[Store][boltdb] save instance to kv error, %v", err)
    90  			return err
    91  		}
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  // UpdateInstance Update instance
    98  func (i *instanceStore) UpdateInstance(instance *model.Instance) error {
    99  
   100  	properties := make(map[string]interface{})
   101  	properties[insFieldProto] = instance.Proto
   102  	curr := time.Now()
   103  	properties[insFieldModifyTime] = curr
   104  	instance.Proto.Mtime = &wrappers.StringValue{Value: commontime.Time2String(curr)}
   105  
   106  	if err := i.handler.UpdateValue(tblNameInstance, instance.ID(), properties); err != nil {
   107  		log.Errorf("[Store][boltdb] update instance to kv error, %v", err)
   108  		return err
   109  	}
   110  
   111  	return nil
   112  }
   113  
   114  // DeleteInstance Delete an instance
   115  func (i *instanceStore) DeleteInstance(instanceID string) error {
   116  
   117  	properties := make(map[string]interface{})
   118  	properties[insFieldValid] = false
   119  	properties[insFieldModifyTime] = time.Now()
   120  
   121  	if err := i.handler.UpdateValue(tblNameInstance, instanceID, properties); err != nil {
   122  		log.Errorf("[Store][boltdb] delete instance from kv error, %v", err)
   123  		return err
   124  	}
   125  
   126  	return nil
   127  }
   128  
   129  // BatchDeleteInstances Delete instances in batch
   130  func (i *instanceStore) BatchDeleteInstances(ids []interface{}) error {
   131  
   132  	if len(ids) == 0 {
   133  		return nil
   134  	}
   135  
   136  	for _, id := range ids {
   137  
   138  		properties := make(map[string]interface{})
   139  		properties[insFieldValid] = false
   140  		properties[insFieldModifyTime] = time.Now()
   141  
   142  		if err := i.handler.UpdateValue(tblNameInstance, id.(string), properties); err != nil {
   143  			log.Errorf("[Store][boltdb] batch delete instance from kv error, %v", err)
   144  			return err
   145  		}
   146  	}
   147  	return nil
   148  }
   149  
   150  // CleanInstance Delete an instance
   151  func (i *instanceStore) CleanInstance(instanceID string) error {
   152  	if err := i.handler.DeleteValues(tblNameInstance, []string{instanceID}); err != nil {
   153  		log.Errorf("[Store][boltdb] delete instance from kv error, %v", err)
   154  		return err
   155  	}
   156  	return nil
   157  }
   158  
   159  // BatchGetInstanceIsolate Check whether the ID exists, and return the query results of all IDs
   160  func (i *instanceStore) BatchGetInstanceIsolate(ids map[string]bool) (map[string]bool, error) {
   161  
   162  	if len(ids) == 0 {
   163  		return nil, nil
   164  	}
   165  
   166  	keys := make([]string, len(ids))
   167  	pos := 0
   168  	for k := range ids {
   169  		keys[pos] = k
   170  		pos++
   171  	}
   172  
   173  	result, err := i.handler.LoadValues(tblNameInstance, keys, &model.Instance{})
   174  	if err != nil {
   175  		log.Errorf("[Store][boltdb] list instance in kv error, %v", err)
   176  		return nil, err
   177  	}
   178  
   179  	if len(result) == 0 {
   180  		return ids, nil
   181  	}
   182  
   183  	for id, val := range result {
   184  		ins := val.(*model.Instance)
   185  		if !ins.Valid {
   186  			continue
   187  		}
   188  
   189  		ids[id] = ins.Proto.GetIsolate().GetValue()
   190  	}
   191  
   192  	return ids, nil
   193  }
   194  
   195  // GetInstancesBrief Get the token associated with the instance
   196  func (i *instanceStore) GetInstancesBrief(ids map[string]bool) (map[string]*model.Instance, error) {
   197  
   198  	if len(ids) == 0 {
   199  		return nil, nil
   200  	}
   201  
   202  	fields := []string{insFieldProto, insFieldValid}
   203  
   204  	// find all instances with given ids
   205  	inss, err := i.handler.LoadValuesByFilter(tblNameInstance, fields, &model.Instance{},
   206  		func(m map[string]interface{}) bool {
   207  			valid, ok := m[insFieldValid]
   208  			if ok && !valid.(bool) {
   209  				return false
   210  			}
   211  
   212  			insProto, ok := m[insFieldProto]
   213  			if !ok {
   214  				return false
   215  			}
   216  			id := insProto.(*apiservice.Instance).GetId().GetValue()
   217  			_, ok = ids[id]
   218  			return ok
   219  		})
   220  	if err != nil {
   221  		log.Errorf("[Store][boltdb] load instance error, %v", err)
   222  		return nil, err
   223  	}
   224  
   225  	// find the service corresponding to the instance and get the serviceToken
   226  	serviceIDs := make(map[string]bool)
   227  	for _, ins := range inss {
   228  		serviceID := ins.(*model.Instance).ServiceID
   229  		serviceIDs[serviceID] = true
   230  	}
   231  
   232  	fields = []string{SvcFieldID, SvcFieldValid}
   233  	services, err := i.handler.LoadValuesByFilter(tblNameService, fields, &model.Service{},
   234  		func(m map[string]interface{}) bool {
   235  			valid, ok := m[insFieldValid]
   236  			if ok && !valid.(bool) {
   237  				return false
   238  			}
   239  
   240  			svcId, ok := m[SvcFieldID]
   241  			if !ok {
   242  				return false
   243  			}
   244  			id := svcId.(string)
   245  			_, ok = serviceIDs[id]
   246  			return ok
   247  		})
   248  
   249  	// assemble return data
   250  	out := make(map[string]*model.Instance, len(ids))
   251  	var item model.ExpandInstanceStore
   252  	var instance model.InstanceStore
   253  	item.ServiceInstance = &instance
   254  
   255  	for _, ins := range inss {
   256  		tempIns := ins.(*model.Instance)
   257  		svc, ok := services[tempIns.ServiceID]
   258  		if !ok {
   259  			log.Errorf("[Store][boltdb] can not find instance service , instanceId is %s", tempIns.ID())
   260  			return nil, errors.New("can not find instance service")
   261  		}
   262  		tempService := svc.(*model.Service)
   263  		instance.ID = tempIns.ID()
   264  		instance.Host = tempIns.Host()
   265  		instance.Port = tempIns.Port()
   266  		item.ServiceName = tempService.Name
   267  		item.Namespace = tempService.Namespace
   268  		item.ServiceToken = tempService.Token
   269  		item.ServicePlatformID = tempService.PlatformID
   270  
   271  		out[instance.ID] = model.ExpandStore2Instance(&item)
   272  	}
   273  
   274  	return out, nil
   275  }
   276  
   277  // GetInstance Query the details of an instance
   278  func (i *instanceStore) GetInstance(instanceID string) (*model.Instance, error) {
   279  	fields := []string{insFieldProto, insFieldValid}
   280  	ins, err := i.handler.LoadValuesByFilter(tblNameInstance, fields, &model.Instance{},
   281  		func(m map[string]interface{}) bool {
   282  			if insValid, _ := m[insFieldValid].(bool); !insValid {
   283  				return false
   284  			}
   285  			insProto, ok := m[insFieldProto]
   286  			if !ok {
   287  				return false
   288  			}
   289  			id := insProto.(*apiservice.Instance).GetId().GetValue()
   290  			return id == instanceID
   291  		})
   292  	if err != nil {
   293  		log.Errorf("[Store][boltdb] load instance from kv error, %v", err)
   294  		return nil, err
   295  	}
   296  	instance, ok := ins[instanceID]
   297  	if !ok {
   298  		return nil, nil
   299  	}
   300  	return instance.(*model.Instance), nil
   301  }
   302  
   303  // GetInstancesCount Get the total number of instances
   304  func (i *instanceStore) GetInstancesCount() (uint32, error) {
   305  
   306  	count, err := i.handler.CountValues(tblNameInstance)
   307  	if err != nil {
   308  		log.Errorf("[Store][boltdb] get instance count error, %v", err)
   309  		return 0, err
   310  	}
   311  
   312  	return uint32(count), nil
   313  }
   314  
   315  // GetInstancesCountTx Get the total number of instances
   316  func (i *instanceStore) GetInstancesCountTx(tx store.Tx) (uint32, error) {
   317  	dbTx, _ := tx.GetDelegateTx().(*bolt.Tx)
   318  	count, err := countValues(dbTx, tblNameInstance)
   319  	if err != nil {
   320  		log.Errorf("[Store][boltdb] get instance count error, %v", err)
   321  		return 0, err
   322  	}
   323  
   324  	return uint32(count), nil
   325  }
   326  
   327  // GetInstancesMainByService Get instances based on service and Host
   328  func (i *instanceStore) GetInstancesMainByService(serviceID, host string) ([]*model.Instance, error) {
   329  
   330  	// select by service_id and host
   331  	fields := []string{insFieldServiceID, insFieldProto, insFieldValid}
   332  
   333  	instances, err := i.handler.LoadValuesByFilter(tblNameInstance, fields, &model.Instance{},
   334  		func(m map[string]interface{}) bool {
   335  			valid, ok := m[insFieldValid]
   336  			if ok && !valid.(bool) {
   337  				return false
   338  			}
   339  
   340  			sId, ok := m[insFieldServiceID]
   341  			if !ok {
   342  				return false
   343  			}
   344  			insProto, ok := m[insFieldProto]
   345  			if !ok {
   346  				return false
   347  			}
   348  
   349  			svcId := sId.(string)
   350  			h := insProto.(*apiservice.Instance).GetHost().GetValue()
   351  			if svcId != serviceID {
   352  				return false
   353  			}
   354  			if h != host {
   355  				return false
   356  			}
   357  			return true
   358  		})
   359  	if err != nil {
   360  		log.Errorf("[Store][boltdb] load instance from kv error, %v", err)
   361  		return nil, err
   362  	}
   363  
   364  	return getRealInstancesList(instances, 0, uint32(len(instances))), nil
   365  }
   366  
   367  // GetExpandInstances View instance details and corresponding number according to filter conditions
   368  func (i *instanceStore) GetExpandInstances(filter, metaFilter map[string]string,
   369  	offset uint32, limit uint32) (uint32, []*model.Instance, error) {
   370  	if limit == 0 {
   371  		return 0, make([]*model.Instance, 0), nil
   372  	}
   373  
   374  	// find service
   375  	name, isServiceName := filter["name"]
   376  	namespace, isNamespace := filter["namespace"]
   377  
   378  	svcIDFilterSet := make(map[string]struct{}, 0)
   379  	if isNamespace || isServiceName {
   380  		sStore := serviceStore{handler: i.handler}
   381  		svcs, err := sStore.GetServiceByNameAndNamespace(name, namespace)
   382  		if err != nil {
   383  			log.Errorf("[Store][boltdb] find service error, %v", err)
   384  			return 0, nil, err
   385  		}
   386  		for _, svc := range svcs {
   387  			svcIDFilterSet[svc.ID] = struct{}{}
   388  		}
   389  		if len(svcIDFilterSet) == 0 {
   390  			return 0, make([]*model.Instance, 0), nil
   391  		}
   392  	}
   393  
   394  	svcIdsTmp := make(map[string]struct{})
   395  	fields := []string{insFieldProto, insFieldServiceID, insFieldValid}
   396  
   397  	instances, err := i.handler.LoadValuesByFilter(tblNameInstance, fields, &model.Instance{},
   398  		func(m map[string]interface{}) bool {
   399  			valid, ok := m[insFieldValid]
   400  			if ok && !valid.(bool) {
   401  				return false
   402  			}
   403  
   404  			insProto, ok := m[insFieldProto]
   405  			if !ok {
   406  				return false
   407  			}
   408  			ins := insProto.(*apiservice.Instance)
   409  			host, isHost := filter["host"]
   410  			port, isPort := filter["port"]
   411  			protocol, isProtocol := filter["protocol"]
   412  			version, isVersion := filter["version"]
   413  			healthy, isHealthy := filter["health_status"]
   414  			isolate, isIsolate := filter["isolate"]
   415  			id, isId := filter["id"]
   416  
   417  			if isId {
   418  				if utils.IsWildName(id) {
   419  					if !utils.IsWildMatch(ins.GetId().GetValue(), id) {
   420  						return false
   421  					}
   422  				} else {
   423  					if id != ins.GetId().GetValue() {
   424  						return false
   425  					}
   426  				}
   427  			}
   428  			if isHost && host != ins.GetHost().GetValue() {
   429  				return false
   430  			}
   431  			if isPort && port != strconv.Itoa(int(ins.GetPort().GetValue())) {
   432  				return false
   433  			}
   434  			if isProtocol && protocol != ins.GetProtocol().GetValue() {
   435  				return false
   436  			}
   437  			if isVersion && version != ins.GetVersion().GetValue() {
   438  				return false
   439  			}
   440  			if isHealthy && compareParam2BoolNotEqual(healthy, ins.GetHealthy().GetValue()) {
   441  				return false
   442  			}
   443  			if isIsolate && compareParam2BoolNotEqual(isolate, ins.GetIsolate().GetValue()) {
   444  				return false
   445  			}
   446  
   447  			// 如果提供了 serviceName 或者 namespaceName 才过滤 serviceID
   448  			if isServiceName || isNamespace {
   449  				// filter serviceID
   450  				sID, ok := m["ServiceID"]
   451  				if !ok {
   452  					return false
   453  				}
   454  				sIDStr, strOK := sID.(string)
   455  				if !strOK {
   456  					return false
   457  				}
   458  				if _, ok := svcIDFilterSet[sIDStr]; !ok {
   459  					return false
   460  				}
   461  			}
   462  
   463  			// filter metadata
   464  			if len(metaFilter) > 0 {
   465  				var key, value string
   466  				for k, v := range metaFilter {
   467  					key = k
   468  					value = v
   469  					break
   470  				}
   471  
   472  				insV, ok := ins.GetMetadata()[key]
   473  				if !ok || insV != value {
   474  					return false
   475  				}
   476  			}
   477  			svcIdsTmp[m["ServiceID"].(string)] = struct{}{}
   478  			return true
   479  		})
   480  	if err != nil {
   481  		log.Errorf("[Store][boltdb] load instance from kv error, %v", err)
   482  		return 0, nil, err
   483  	}
   484  
   485  	svcIds := make([]string, len(svcIdsTmp))
   486  	pos := 0
   487  	for k := range svcIdsTmp {
   488  		svcIds[pos] = k
   489  		pos++
   490  	}
   491  	svcRets, err := i.handler.LoadValues(tblNameService, svcIds, &model.Service{})
   492  	svcRets, err = i.handler.LoadValuesAll(tblNameService, &model.Service{})
   493  	if err != nil {
   494  		log.Errorf("[Store][boltdb] load service from kv error, %v", err)
   495  		return 0, nil, err
   496  	}
   497  	for _, v := range instances {
   498  		ins := v.(*model.Instance)
   499  		service, ok := svcRets[ins.ServiceID]
   500  		if !ok {
   501  			log.Errorf("[Store][boltdb] no found instance relate service, "+
   502  				"instance-id: %s, service-id: %s", ins.ID(), ins.ServiceID)
   503  			return 0, nil, errors.New("no found instance relate service")
   504  		}
   505  		ins.Proto.Service = wrapperspb.String(service.(*model.Service).Name)
   506  		ins.Proto.Namespace = wrapperspb.String(service.(*model.Service).Namespace)
   507  	}
   508  
   509  	totalCount := uint32(len(instances))
   510  
   511  	return totalCount, getRealInstancesList(instances, offset, limit), nil
   512  }
   513  
   514  // GetMoreInstances Get incremental instances according to mtime
   515  func (i *instanceStore) GetMoreInstances(tx store.Tx, mtime time.Time, firstUpdate, needMeta bool,
   516  	serviceID []string) (map[string]*model.Instance, error) {
   517  
   518  	dbTx, _ := tx.GetDelegateTx().(*bolt.Tx)
   519  
   520  	fields := []string{insFieldProto, insFieldServiceID, insFieldValid}
   521  	svcIdMap := make(map[string]bool)
   522  	for _, s := range serviceID {
   523  		svcIdMap[s] = true
   524  	}
   525  
   526  	instances := make(map[string]interface{})
   527  	err := loadValuesByFilter(dbTx, tblNameInstance, fields, &model.Instance{},
   528  		func(m map[string]interface{}) bool {
   529  
   530  			if firstUpdate {
   531  				valid, ok := m[insFieldValid]
   532  				if ok && !valid.(bool) {
   533  					return false
   534  				}
   535  			}
   536  
   537  			insProto, ok := m[insFieldProto]
   538  			if !ok {
   539  				return false
   540  			}
   541  			svcId, ok := m[insFieldServiceID]
   542  			if !ok {
   543  				return false
   544  			}
   545  			ins := insProto.(*apiservice.Instance)
   546  			serviceId := svcId.(string)
   547  
   548  			insMtime, err := time.Parse("2006-01-02 15:04:05", ins.GetMtime().GetValue())
   549  			if err != nil {
   550  				log.Errorf("[Store][boltdb] parse instance mtime error, %v", err)
   551  				return false
   552  			}
   553  
   554  			if insMtime.Before(mtime) {
   555  				return false
   556  			}
   557  
   558  			if len(svcIdMap) > 0 {
   559  				_, ok = svcIdMap[serviceId]
   560  				if !ok {
   561  					return false
   562  				}
   563  			}
   564  
   565  			return true
   566  		}, instances)
   567  
   568  	if err != nil {
   569  		log.Errorf("[Store][boltdb] load instance from kv error, %v", err)
   570  		return nil, err
   571  	}
   572  
   573  	return toInstance(instances), nil
   574  }
   575  
   576  // BatchSetInstanceHealthStatus 批量设置实例的健康状态
   577  func (i *instanceStore) BatchSetInstanceHealthStatus(ids []interface{}, healthy int, revision string) error {
   578  	for _, id := range ids {
   579  		if err := i.SetInstanceHealthStatus(id.(string), healthy, revision); err != nil {
   580  			return err
   581  		}
   582  	}
   583  	return nil
   584  }
   585  
   586  // SetInstanceHealthStatus Set the health status of the instance
   587  func (i *instanceStore) SetInstanceHealthStatus(instanceID string, flag int, revision string) error {
   588  
   589  	// get instance
   590  	fields := []string{insFieldProto}
   591  
   592  	instances, err := i.handler.LoadValuesByFilter(tblNameInstance, fields, &model.Instance{},
   593  		func(m map[string]interface{}) bool {
   594  			insProto, ok := m[insFieldProto]
   595  			if !ok {
   596  				return false
   597  			}
   598  			insId := insProto.(*apiservice.Instance).GetId().GetValue()
   599  
   600  			return insId == instanceID
   601  		})
   602  	if err != nil {
   603  		log.Errorf("[Store][boltdb] load instance from kv error, %v", err)
   604  		return err
   605  	}
   606  	if len(instances) == 0 {
   607  		msg := fmt.Sprintf("cant not find instance in kv, %s", instanceID)
   608  		log.Errorf(msg)
   609  		return nil
   610  	}
   611  
   612  	// set status
   613  	ins := instances[instanceID].(*model.Instance)
   614  	var healthy bool
   615  	if flag == 0 {
   616  		healthy = false
   617  	} else {
   618  		healthy = true
   619  	}
   620  	ins.Proto.Healthy.Value = healthy
   621  	ins.Proto.Revision.Value = revision
   622  
   623  	properties := make(map[string]interface{})
   624  	properties[insFieldProto] = ins.Proto
   625  	curr := time.Now()
   626  	properties[insFieldModifyTime] = curr
   627  	ins.Proto.Mtime = &wrappers.StringValue{Value: commontime.Time2String(curr)}
   628  
   629  	err = i.handler.UpdateValue(tblNameInstance, instanceID, properties)
   630  	if err != nil {
   631  		log.Errorf("[Store][boltdb] update instance error %v", err)
   632  		return err
   633  	}
   634  
   635  	return nil
   636  }
   637  
   638  // BatchSetInstanceIsolate Modify the isolation status of instances in batches
   639  func (i *instanceStore) BatchSetInstanceIsolate(ids []interface{}, isolate int, revision string) error {
   640  
   641  	insIds := make(map[string]bool)
   642  	for _, id := range ids {
   643  		insIds[id.(string)] = true
   644  	}
   645  	var isolateStatus bool
   646  	if isolate == 0 {
   647  		isolateStatus = false
   648  	} else {
   649  		isolateStatus = true
   650  	}
   651  
   652  	fields := []string{insFieldProto}
   653  
   654  	// get all instances by given ids
   655  	instances, err := i.handler.LoadValuesByFilter(tblNameInstance, fields, &model.Instance{},
   656  		func(m map[string]interface{}) bool {
   657  			proto, ok := m[insFieldProto]
   658  			if !ok {
   659  				return false
   660  			}
   661  			insId := proto.(*apiservice.Instance).GetId().GetValue()
   662  
   663  			_, ok = insIds[insId]
   664  			return ok
   665  		})
   666  	if err != nil {
   667  		log.Errorf("[Store][boltdb] get instance from kv error, %v", err)
   668  		return err
   669  	}
   670  	if len(instances) == 0 {
   671  		msg := fmt.Sprintf("cant not find instance in kv, %v", ids)
   672  		log.Errorf(msg)
   673  		return nil
   674  	}
   675  
   676  	for id, ins := range instances {
   677  		instance := ins.(*model.Instance).Proto
   678  		instance.Isolate.Value = isolateStatus
   679  		instance.Revision.Value = revision
   680  
   681  		properties := make(map[string]interface{})
   682  		properties[insFieldProto] = instance
   683  		curr := time.Now()
   684  		properties[insFieldModifyTime] = curr
   685  		instance.Mtime = &wrappers.StringValue{Value: commontime.Time2String(curr)}
   686  		err = i.handler.UpdateValue(tblNameInstance, id, properties)
   687  		if err != nil {
   688  			log.Errorf("[Store][boltdb] update instance in set instance isolate error, %v", err)
   689  			return err
   690  		}
   691  	}
   692  
   693  	return nil
   694  }
   695  
   696  // BatchAppendInstanceMetadata 追加实例 metadata
   697  func (i *instanceStore) BatchAppendInstanceMetadata(requests []*store.InstanceMetadataRequest) error {
   698  	if len(requests) == 0 {
   699  		return nil
   700  	}
   701  	return i.handler.Execute(true, func(tx *bolt.Tx) error {
   702  		values := map[string]interface{}{}
   703  		fields := []string{insFieldProto, insFieldValid}
   704  		if err := loadValuesByFilter(tx, tblNameInstance, fields, &model.Instance{},
   705  			func(m map[string]interface{}) bool {
   706  				valid, ok := m[insFieldValid]
   707  				if ok && !valid.(bool) {
   708  					return false
   709  				}
   710  				proto, ok := m[insFieldProto]
   711  				if !ok {
   712  					return false
   713  				}
   714  				insId := proto.(*apiservice.Instance).GetId().GetValue()
   715  				for i := range requests {
   716  					if requests[i].InstanceID == insId {
   717  						return true
   718  					}
   719  				}
   720  				return false
   721  			}, values); err != nil {
   722  			log.Errorf("[Store][boltdb] do batch append InstanceMetadata get instances error, %v", err)
   723  			return err
   724  		}
   725  		if len(values) == 0 {
   726  			return nil
   727  		}
   728  		for i := range requests {
   729  			instanceID := requests[i].InstanceID
   730  			val, ok := values[instanceID]
   731  			if !ok {
   732  				return nil
   733  			}
   734  			ins := val.(*model.Instance)
   735  			if len(ins.Proto.GetMetadata()) == 0 {
   736  				ins.Proto.Metadata = map[string]string{}
   737  			}
   738  			for k, v := range requests[i].Metadata {
   739  				ins.Proto.Metadata[k] = v
   740  			}
   741  			properties := make(map[string]interface{})
   742  			properties[insFieldProto] = ins.Proto
   743  			properties[CommonFieldRevision] = requests[i].Revision
   744  			properties[insFieldModifyTime] = time.Now()
   745  			if err := updateValue(tx, tblNameInstance, instanceID, properties); err != nil {
   746  				log.Errorf("[Store][boltdb] do batch append InstanceMetadata update instance by %s error, %v",
   747  					instanceID, err)
   748  				return err
   749  			}
   750  		}
   751  		return nil
   752  	})
   753  }
   754  
   755  // BatchRemoveInstanceMetadata 删除实例指定的 metadata
   756  func (i *instanceStore) BatchRemoveInstanceMetadata(requests []*store.InstanceMetadataRequest) error {
   757  	if len(requests) == 0 {
   758  		return nil
   759  	}
   760  	return i.handler.Execute(true, func(tx *bolt.Tx) error {
   761  		values := map[string]interface{}{}
   762  		fields := []string{insFieldProto, insFieldValid}
   763  		if err := loadValuesByFilter(tx, tblNameInstance, fields, &model.Instance{},
   764  			func(m map[string]interface{}) bool {
   765  				valid, ok := m[insFieldValid]
   766  				if ok && !valid.(bool) {
   767  					return false
   768  				}
   769  				proto, ok := m[insFieldProto]
   770  				if !ok {
   771  					return false
   772  				}
   773  				insId := proto.(*apiservice.Instance).GetId().GetValue()
   774  				for i := range requests {
   775  					if requests[i].InstanceID == insId {
   776  						return true
   777  					}
   778  				}
   779  				return false
   780  			}, values); err != nil {
   781  			log.Errorf("[Store][boltdb] do batch remove InstanceMetadata get instances error, %v", err)
   782  			return err
   783  		}
   784  		if len(values) == 0 {
   785  			return nil
   786  		}
   787  		for i := range requests {
   788  			instanceID := requests[i].InstanceID
   789  			val, ok := values[instanceID]
   790  			if !ok {
   791  				continue
   792  			}
   793  			ins := val.(*model.Instance)
   794  			if len(ins.Proto.GetMetadata()) == 0 {
   795  				ins.Proto.Metadata = map[string]string{}
   796  			}
   797  			for p := range requests[i].Keys {
   798  				delete(ins.Proto.Metadata, requests[i].Keys[p])
   799  			}
   800  			properties := make(map[string]interface{})
   801  			properties[insFieldProto] = ins.Proto
   802  			properties[CommonFieldRevision] = requests[i].Revision
   803  			properties[insFieldModifyTime] = time.Now()
   804  			if err := updateValue(tx, tblNameInstance, instanceID, properties); err != nil {
   805  				log.Errorf("[Store][boltdb] do batch remove InstanceMetadata update instance by %s error, %v",
   806  					instanceID, err)
   807  				return err
   808  			}
   809  		}
   810  		return nil
   811  	})
   812  }
   813  
   814  func toInstance(m map[string]interface{}) map[string]*model.Instance {
   815  	insMap := make(map[string]*model.Instance)
   816  	for k, v := range m {
   817  		insMap[k] = v.(*model.Instance)
   818  	}
   819  
   820  	return insMap
   821  }
   822  
   823  func getRealInstancesList(originServices map[string]interface{}, offset, limit uint32) []*model.Instance {
   824  	instances := make([]*model.Instance, 0)
   825  	beginIndex := offset
   826  	endIndex := beginIndex + limit
   827  	totalCount := uint32(len(originServices))
   828  	// handle invalid limit offset
   829  	if totalCount == 0 {
   830  		return instances
   831  	}
   832  	if beginIndex >= endIndex {
   833  		return instances
   834  	}
   835  	if beginIndex >= totalCount {
   836  		return instances
   837  	}
   838  	if endIndex > totalCount {
   839  		endIndex = totalCount
   840  	}
   841  
   842  	for _, s := range originServices {
   843  		instances = append(instances, s.(*model.Instance))
   844  	}
   845  
   846  	sort.Slice(instances, func(i, j int) bool {
   847  		// sort by modify time
   848  		if instances[i].ModifyTime.After(instances[j].ModifyTime) {
   849  			return true
   850  		} else if instances[i].ModifyTime.Before(instances[j].ModifyTime) {
   851  			return false
   852  		} else {
   853  			return strings.Compare(instances[i].ID(), instances[j].ID()) < 0
   854  		}
   855  	})
   856  
   857  	return instances[beginIndex:endIndex]
   858  }
   859  
   860  func initInstance(instance []*model.Instance) {
   861  
   862  	if len(instance) == 0 {
   863  		return
   864  	}
   865  
   866  	for _, ins := range instance {
   867  		if ins != nil {
   868  			currT := time.Now()
   869  			timeStamp := commontime.Time2String(currT)
   870  			if ins.Proto != nil {
   871  				if ins.Proto.GetMtime().GetValue() == "" {
   872  					ins.Proto.Mtime = &wrappers.StringValue{Value: timeStamp}
   873  				}
   874  				if ins.Proto.GetCtime().GetValue() == "" {
   875  					ins.Proto.Ctime = &wrappers.StringValue{Value: timeStamp}
   876  				}
   877  			}
   878  			ins.Valid = true
   879  			ins.ModifyTime = currT
   880  		}
   881  	}
   882  }
   883  
   884  func compareParam2BoolNotEqual(param string, b bool) bool {
   885  	if param == "0" && !b {
   886  		return false
   887  	}
   888  	if param == "1" && b {
   889  		return false
   890  	}
   891  	return true
   892  }