github.com/polarismesh/polaris@v1.17.8/store/mysql/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 sqldb
    19  
    20  import (
    21  	"database/sql"
    22  	"errors"
    23  	"fmt"
    24  	"strings"
    25  	"time"
    26  
    27  	apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage"
    28  	"go.uber.org/zap"
    29  
    30  	"github.com/polarismesh/polaris/common/model"
    31  	"github.com/polarismesh/polaris/store"
    32  )
    33  
    34  // instanceStore 实现了InstanceStore接口
    35  type instanceStore struct {
    36  	master *BaseDB // 大部分操作都用主数据库
    37  	slave  *BaseDB // 缓存相关的读取,请求到slave
    38  }
    39  
    40  // AddInstance 添加实例
    41  func (ins *instanceStore) AddInstance(instance *model.Instance) error {
    42  	err := RetryTransaction("addInstance", func() error {
    43  		return ins.addInstance(instance)
    44  	})
    45  	return store.Error(err)
    46  }
    47  
    48  // addInstance
    49  func (ins *instanceStore) addInstance(instance *model.Instance) error {
    50  	tx, err := ins.master.Begin()
    51  	if err != nil {
    52  		log.Errorf("[Store][database] add instance tx begin err: %s", err.Error())
    53  		return err
    54  	}
    55  	defer func() { _ = tx.Rollback() }()
    56  
    57  	// 新增数据之前,必须先清理老数据
    58  	if err := cleanInstance(tx, instance.ID()); err != nil {
    59  		return err
    60  	}
    61  
    62  	if err := addMainInstance(tx, instance); err != nil {
    63  		log.Errorf("[Store][database] add instance main insert err: %s", err.Error())
    64  		return err
    65  	}
    66  
    67  	if err := addInstanceCheck(tx, instance); err != nil {
    68  		return err
    69  	}
    70  
    71  	if err := updateInstanceMeta(tx, instance); err != nil {
    72  		log.Errorf("[Store][database] add instance meta err: %s", err.Error())
    73  		return err
    74  	}
    75  
    76  	if err := tx.Commit(); err != nil {
    77  		log.Errorf("[Store][database] add instance commit tx err: %s", err.Error())
    78  		return err
    79  	}
    80  
    81  	return nil
    82  }
    83  
    84  // BatchAddInstances 批量增加实例
    85  func (ins *instanceStore) BatchAddInstances(instances []*model.Instance) error {
    86  
    87  	err := RetryTransaction("batchAddInstances", func() error {
    88  		return ins.batchAddInstances(instances)
    89  	})
    90  	return store.Error(err)
    91  }
    92  
    93  // batchAddInstances batch add instances
    94  func (ins *instanceStore) batchAddInstances(instances []*model.Instance) error {
    95  	tx, err := ins.master.Begin()
    96  	if err != nil {
    97  		log.Errorf("[Store][database] batch add instances begin tx err: %s", err.Error())
    98  		return err
    99  	}
   100  	defer func() { _ = tx.Rollback() }()
   101  
   102  	if err := batchAddMainInstances(tx, instances); err != nil {
   103  		log.Errorf("[Store][database] batch add main instances err: %s", err.Error())
   104  		return err
   105  	}
   106  	if err := batchAddInstanceCheck(tx, instances); err != nil {
   107  		log.Errorf("[Store][database] batch add instance check err: %s", err.Error())
   108  		return err
   109  	}
   110  	if err := batchDeleteInstanceMeta(tx, instances); err != nil {
   111  		log.Errorf("[Store][database] batch delete instance metadata err: %s", err.Error())
   112  		return err
   113  	}
   114  	if err := batchAddInstanceMeta(tx, instances); err != nil {
   115  		log.Errorf("[Store][database] batch add instance metadata err: %s", err.Error())
   116  		return err
   117  	}
   118  
   119  	if err := tx.Commit(); err != nil {
   120  		log.Errorf("[Store][database] batch add instance commit tx err: %s", err.Error())
   121  		return err
   122  	}
   123  
   124  	return nil
   125  }
   126  
   127  // UpdateInstance 更新实例
   128  func (ins *instanceStore) UpdateInstance(instance *model.Instance) error {
   129  	err := RetryTransaction("updateInstance", func() error {
   130  		return ins.updateInstance(instance)
   131  	})
   132  	if err == nil {
   133  		return nil
   134  	}
   135  
   136  	serr := store.Error(err)
   137  	if store.Code(serr) == store.DuplicateEntryErr {
   138  		serr = store.NewStatusError(store.DataConflictErr, err.Error())
   139  	}
   140  	return serr
   141  }
   142  
   143  // updateInstance update instance
   144  func (ins *instanceStore) updateInstance(instance *model.Instance) error {
   145  	tx, err := ins.master.Begin()
   146  	if err != nil {
   147  		log.Errorf("[Store][database] update instance tx begin err: %s", err.Error())
   148  		return err
   149  	}
   150  	defer func() { _ = tx.Rollback() }()
   151  
   152  	// 更新main表
   153  	if err := updateInstanceMain(tx, instance); err != nil {
   154  		log.Errorf("[Store][database] update instance main err: %s", err.Error())
   155  		return err
   156  	}
   157  	// 更新health check表
   158  	if err := updateInstanceCheck(tx, instance); err != nil {
   159  		log.Errorf("[Store][database] update instance check err: %s", err.Error())
   160  		return err
   161  	}
   162  	// 更新meta表
   163  	if err := updateInstanceMeta(tx, instance); err != nil {
   164  		log.Errorf("[Store][database] update instance meta err: %s", err.Error())
   165  		return err
   166  	}
   167  
   168  	if err := tx.Commit(); err != nil {
   169  		log.Errorf("[Store][database] update instance commit tx err: %s", err.Error())
   170  		return err
   171  	}
   172  
   173  	return nil
   174  }
   175  
   176  // CleanInstance 清理数据
   177  func (ins *instanceStore) CleanInstance(instanceID string) error {
   178  	return RetryTransaction("cleanInstance", func() error {
   179  		return ins.master.processWithTransaction("cleanInstance", func(tx *BaseTx) error {
   180  			if err := cleanInstance(tx, instanceID); err != nil {
   181  				return err
   182  			}
   183  
   184  			if err := tx.Commit(); err != nil {
   185  				log.Errorf("[Store][database] clean instance commit tx err: %s", err.Error())
   186  				return err
   187  			}
   188  
   189  			return nil
   190  		})
   191  	})
   192  }
   193  
   194  // cleanInstance 清理数据
   195  func cleanInstance(tx *BaseTx, instanceID string) error {
   196  	log.Infof("[Store][database] clean instance(%s)", instanceID)
   197  	cleanIns := "delete from instance where id = ? and flag = 1"
   198  	if _, err := tx.Exec(cleanIns, instanceID); err != nil {
   199  		log.Errorf("[Store][database] clean instance(%s), err: %s", instanceID, err.Error())
   200  		return store.Error(err)
   201  	}
   202  	cleanMeta := "delete from instance_metadata where id = ?"
   203  	if _, err := tx.Exec(cleanMeta, instanceID); err != nil {
   204  		log.Errorf("[Store][database] clean instance_metadata(%s), err: %s", instanceID, err.Error())
   205  		return store.Error(err)
   206  	}
   207  	cleanCheck := "delete from health_check where id = ?"
   208  	if _, err := tx.Exec(cleanCheck, instanceID); err != nil {
   209  		log.Errorf("[Store][database] clean health_check(%s), err: %s", instanceID, err.Error())
   210  		return store.Error(err)
   211  	}
   212  	return nil
   213  }
   214  
   215  // DeleteInstance 删除一个实例,删除实例实际上是把flag置为1
   216  func (ins *instanceStore) DeleteInstance(instanceID string) error {
   217  	if instanceID == "" {
   218  		return errors.New("delete Instance Missing instance id")
   219  	}
   220  	return RetryTransaction("deleteInstance", func() error {
   221  		return ins.master.processWithTransaction("deleteInstance", func(tx *BaseTx) error {
   222  			str := "update instance set flag = 1, mtime = sysdate() where `id` = ?"
   223  			if _, err := tx.Exec(str, instanceID); err != nil {
   224  				return store.Error(err)
   225  			}
   226  
   227  			if err := tx.Commit(); err != nil {
   228  				log.Errorf("[Store][database] delete instance commit tx err: %s", err.Error())
   229  				return err
   230  			}
   231  
   232  			return nil
   233  		})
   234  	})
   235  }
   236  
   237  // BatchDeleteInstances 批量删除实例
   238  func (ins *instanceStore) BatchDeleteInstances(ids []interface{}) error {
   239  	return RetryTransaction("batchDeleteInstance", func() error {
   240  		return ins.master.processWithTransaction("batchDeleteInstance", func(tx *BaseTx) error {
   241  			if err := BatchOperation("delete-instance", ids, func(objects []interface{}) error {
   242  				if len(objects) == 0 {
   243  					return nil
   244  				}
   245  				str := `update instance set flag = 1, mtime = sysdate() where id in ( ` + PlaceholdersN(len(objects)) + `)`
   246  				_, err := tx.Exec(str, objects...)
   247  				return store.Error(err)
   248  			}); err != nil {
   249  				return err
   250  			}
   251  
   252  			if err := tx.Commit(); err != nil {
   253  				log.Errorf("[Store][database] batch delete instance commit tx err: %s", err.Error())
   254  				return err
   255  			}
   256  
   257  			return nil
   258  		})
   259  	})
   260  }
   261  
   262  // GetInstance 获取单个实例详情,只返回有效的数据
   263  func (ins *instanceStore) GetInstance(instanceID string) (*model.Instance, error) {
   264  	instance, err := ins.getInstance(instanceID)
   265  	if err != nil {
   266  		return nil, err
   267  	}
   268  
   269  	// 如果实例无效,则不返回
   270  	if instance != nil && !instance.Valid {
   271  		return nil, nil
   272  	}
   273  
   274  	return instance, nil
   275  }
   276  
   277  // BatchGetInstanceIsolate 检查实例是否存在
   278  func (ins *instanceStore) BatchGetInstanceIsolate(ids map[string]bool) (map[string]bool, error) {
   279  	if len(ids) == 0 {
   280  		return nil, nil
   281  	}
   282  
   283  	str := "select id, isolate from instance where flag = 0 and id in(" + PlaceholdersN(len(ids)) + ")"
   284  	args := make([]interface{}, 0, len(ids))
   285  	for key := range ids {
   286  		args = append(args, key)
   287  	}
   288  	instanceIsolate := make(map[string]bool, len(ids))
   289  	rows, err := ins.master.Query(str, args...)
   290  	if err != nil {
   291  		log.Errorf("[Store][database] check instances existed query err: %s", err.Error())
   292  		return nil, err
   293  	}
   294  	var idx string
   295  	var isolate int
   296  	for rows.Next() {
   297  		if err := rows.Scan(&idx, &isolate); err != nil {
   298  			log.Errorf("[Store][database] check instances existed scan err: %s", err.Error())
   299  			return nil, err
   300  		}
   301  		instanceIsolate[idx] = model.Int2bool(isolate)
   302  	}
   303  
   304  	return instanceIsolate, nil
   305  }
   306  
   307  // GetInstancesBrief 批量获取实例的serviceID
   308  func (ins *instanceStore) GetInstancesBrief(ids map[string]bool) (map[string]*model.Instance, error) {
   309  	if len(ids) == 0 {
   310  		return nil, nil
   311  	}
   312  
   313  	str := `select instance.id, host, port, name, namespace, token, IFNULL(platform_id,"") from service, instance
   314  		 where instance.flag = 0 and service.flag = 0 
   315  		 and service.id = instance.service_id and instance.id in (` + PlaceholdersN(len(ids)) + ")"
   316  	args := make([]interface{}, 0, len(ids))
   317  	for key := range ids {
   318  		args = append(args, key)
   319  	}
   320  
   321  	rows, err := ins.master.Query(str, args...)
   322  	if err != nil {
   323  		log.Errorf("[Store][database] get instances service token query err: %s", err.Error())
   324  		return nil, err
   325  	}
   326  	defer rows.Close()
   327  
   328  	out := make(map[string]*model.Instance, len(ids))
   329  	var item model.ExpandInstanceStore
   330  	var instance model.InstanceStore
   331  	item.ServiceInstance = &instance
   332  	for rows.Next() {
   333  		if err := rows.Scan(&instance.ID, &instance.Host, &instance.Port,
   334  			&item.ServiceName, &item.Namespace, &item.ServiceToken, &item.ServicePlatformID); err != nil {
   335  			log.Errorf("[Store][database] get instances service token scan err: %s", err.Error())
   336  			return nil, err
   337  		}
   338  
   339  		out[instance.ID] = model.ExpandStore2Instance(&item)
   340  	}
   341  
   342  	return out, nil
   343  }
   344  
   345  // GetInstancesCount 获取有效的实例总数
   346  func (ins *instanceStore) GetInstancesCount() (uint32, error) {
   347  	countStr := "select count(*) from instance where flag = 0"
   348  	var count uint32
   349  	var err error
   350  	Retry("query-instance-row", func() error {
   351  		err = ins.master.QueryRow(countStr).Scan(&count)
   352  		return err
   353  	})
   354  	switch {
   355  	case err == sql.ErrNoRows:
   356  		return 0, nil
   357  	case err != nil:
   358  		log.Errorf("[Store][database] get instances count scan err: %s", err.Error())
   359  		return 0, err
   360  	default:
   361  	}
   362  
   363  	return count, nil
   364  }
   365  
   366  // GetInstancesCountTx .
   367  func (ins *instanceStore) GetInstancesCountTx(tx store.Tx) (uint32, error) {
   368  	dbTx, _ := tx.GetDelegateTx().(*BaseTx)
   369  	countStr := "select count(*) from instance where flag = 0"
   370  	var count uint32
   371  	var err error
   372  	Retry("query-instance-row", func() error {
   373  		err = dbTx.QueryRow(countStr).Scan(&count)
   374  		return err
   375  	})
   376  	switch {
   377  	case err == sql.ErrNoRows:
   378  		return 0, nil
   379  	case err != nil:
   380  		log.Errorf("[Store][database] get instances count scan err: %s", err.Error())
   381  		return 0, err
   382  	default:
   383  	}
   384  
   385  	return count, nil
   386  }
   387  
   388  // GetInstancesMainByService 根据服务和host获取实例
   389  // @note 不包括metadata
   390  func (ins *instanceStore) GetInstancesMainByService(serviceID, host string) ([]*model.Instance, error) {
   391  	// 只查询有效的服务实例
   392  	str := genInstanceSelectSQL() + " where service_id = ? and host = ? and flag = 0"
   393  	rows, err := ins.master.Query(str, serviceID, host)
   394  	if err != nil {
   395  		log.Errorf("[Store][database] get instances main query err: %s", err.Error())
   396  		return nil, err
   397  	}
   398  
   399  	var out []*model.Instance
   400  	err = callFetchInstanceRows(rows, func(entry *model.InstanceStore) (b bool, e error) {
   401  		out = append(out, model.Store2Instance(entry))
   402  		return true, nil
   403  	})
   404  	if err != nil {
   405  		log.Errorf("[Store][database] call fetch instance rows err: %s", err.Error())
   406  		return nil, err
   407  	}
   408  
   409  	return out, nil
   410  }
   411  
   412  // GetExpandInstances 根据过滤条件查看对应服务实例及数目
   413  func (ins *instanceStore) GetExpandInstances(filter, metaFilter map[string]string, offset uint32,
   414  	limit uint32) (uint32, []*model.Instance, error) {
   415  	// 只查询有效的实例列表
   416  	filter["instance.flag"] = "0"
   417  
   418  	out, err := ins.getExpandInstances(filter, metaFilter, offset, limit)
   419  	if err != nil {
   420  		return 0, nil, err
   421  	}
   422  
   423  	num, err := ins.getExpandInstancesCount(filter, metaFilter)
   424  	if err != nil {
   425  		return 0, nil, err
   426  	}
   427  	return num, out, err
   428  }
   429  
   430  // getExpandInstances 根据过滤条件查看对应服务实例
   431  func (ins *instanceStore) getExpandInstances(filter, metaFilter map[string]string, offset uint32,
   432  	limit uint32) ([]*model.Instance, error) {
   433  	// 这种情况意味着,不需要详细的数据,可以不用query了
   434  	if limit == 0 {
   435  		return make([]*model.Instance, 0), nil
   436  	}
   437  	_, isName := filter["name"]
   438  	_, isNamespace := filter["namespace"]
   439  	_, isHost := filter["host"]
   440  	needForceIndex := isName || isNamespace || isHost
   441  
   442  	str := genExpandInstanceSelectSQL(needForceIndex)
   443  	order := &Order{"instance.mtime", "desc"}
   444  	str, args := genWhereSQLAndArgs(str, filter, metaFilter, order, offset, limit)
   445  
   446  	rows, err := ins.master.Query(str, args...)
   447  	if err != nil {
   448  		log.Errorf("[Store][database] get instance by filters query err: %s, str: %s, args: %v", err.Error(), str, args)
   449  		return nil, err
   450  	}
   451  
   452  	out, err := ins.getRowExpandInstances(rows)
   453  	if err != nil {
   454  		log.Errorf("[Store][database] get row instances err: %s", err.Error())
   455  		return nil, err
   456  	}
   457  
   458  	return out, nil
   459  }
   460  
   461  // getExpandInstancesCount 根据过滤条件查看对应服务实例的数目
   462  func (ins *instanceStore) getExpandInstancesCount(filter, metaFilter map[string]string) (uint32, error) {
   463  	str := `select count(*) from instance `
   464  	// 查询条件是否有service表中的字段
   465  	_, isName := filter["name"]
   466  	_, isNamespace := filter["namespace"]
   467  	if isName || isNamespace {
   468  		str += `inner join service on instance.service_id = service.id `
   469  	}
   470  	str, args := genWhereSQLAndArgs(str, filter, metaFilter, nil, 0, 1)
   471  
   472  	var count uint32
   473  	var err error
   474  	Retry("query-instance-row", func() error {
   475  		err = ins.master.QueryRow(str, args...).Scan(&count)
   476  		return err
   477  	})
   478  	switch {
   479  	case err == sql.ErrNoRows:
   480  		log.Errorf("[Store][database] no row with this expand instance filter")
   481  		return count, err
   482  	case err != nil:
   483  		log.Errorf("[Store][database] get expand instance count by filter err: %s", err.Error())
   484  		return count, err
   485  	default:
   486  		return count, nil
   487  	}
   488  }
   489  
   490  // GetMoreInstances 根据mtime获取增量修改数据
   491  // 这里会返回所有的数据的,包括valid=false的数据
   492  // 对于首次拉取,firstUpdate=true,只会拉取flag!=1的数据
   493  func (ins *instanceStore) GetMoreInstances(tx store.Tx, mtime time.Time, firstUpdate, needMeta bool,
   494  	serviceID []string) (map[string]*model.Instance, error) {
   495  
   496  	dbTx, _ := tx.GetDelegateTx().(*BaseTx)
   497  	if needMeta {
   498  		instances, err := ins.getMoreInstancesMainWithMeta(dbTx, mtime, firstUpdate, serviceID)
   499  		if err != nil {
   500  			return nil, err
   501  		}
   502  		return instances, nil
   503  	}
   504  	instances, err := ins.getMoreInstancesMain(dbTx, mtime, firstUpdate, serviceID)
   505  	if err != nil {
   506  		return nil, err
   507  	}
   508  	return instances, nil
   509  }
   510  
   511  // GetInstanceMeta 根据实例ID获取实例的metadata
   512  func (ins *instanceStore) GetInstanceMeta(instanceID string) (map[string]string, error) {
   513  	str := "select `mkey`, `mvalue` from instance_metadata where id = ?"
   514  	rows, err := ins.master.Query(str, instanceID)
   515  	if err != nil {
   516  		log.Errorf("[Store][database] query instance meta err: %s", err.Error())
   517  		return nil, err
   518  	}
   519  	defer rows.Close()
   520  
   521  	out := make(map[string]string)
   522  	var key, value string
   523  	for rows.Next() {
   524  		if err := rows.Scan(&key, &value); err != nil {
   525  			log.Errorf("[Store][database] get instance meta rows scan err: %s", err.Error())
   526  			return nil, err
   527  		}
   528  
   529  		out[key] = value
   530  	}
   531  	if err := rows.Err(); err != nil {
   532  		log.Errorf("[Store][database] get instance meta rows next err: %s", err.Error())
   533  		return nil, err
   534  	}
   535  
   536  	return out, nil
   537  }
   538  
   539  // SetInstanceHealthStatus 设置实例健康状态
   540  func (ins *instanceStore) SetInstanceHealthStatus(instanceID string, flag int, revision string) error {
   541  	return RetryTransaction("setInstanceHealthStatus", func() error {
   542  		return ins.master.processWithTransaction("setInstanceHealthStatus", func(tx *BaseTx) error {
   543  			str := "update instance set health_status = ?, revision = ?, mtime = sysdate() where `id` = ?"
   544  			if _, err := tx.Exec(str, flag, revision, instanceID); err != nil {
   545  				return store.Error(err)
   546  			}
   547  
   548  			if err := tx.Commit(); err != nil {
   549  				log.Errorf("[Store][database] set instance health status commit tx err: %s", err.Error())
   550  				return err
   551  			}
   552  
   553  			return nil
   554  		})
   555  	})
   556  }
   557  
   558  // BatchSetInstanceHealthStatus 批量设置健康状态
   559  func (ins *instanceStore) BatchSetInstanceHealthStatus(ids []interface{}, isolate int, revision string) error {
   560  	return RetryTransaction("batchSetInstanceHealthStatus", func() error {
   561  		return ins.master.processWithTransaction("batchSetInstanceHealthStatus", func(tx *BaseTx) error {
   562  			if err := BatchOperation("set-instance-healthy", ids, func(objects []interface{}) error {
   563  				if len(objects) == 0 {
   564  					return nil
   565  				}
   566  				str := "update instance set health_status = ?, revision = ?, mtime = sysdate() where id in "
   567  				str += "(" + PlaceholdersN(len(objects)) + ")"
   568  				args := make([]interface{}, 0, len(objects)+2)
   569  				args = append(args, isolate)
   570  				args = append(args, revision)
   571  				args = append(args, objects...)
   572  				_, err := tx.Exec(str, args...)
   573  				return store.Error(err)
   574  			}); err != nil {
   575  				return err
   576  			}
   577  
   578  			if err := tx.Commit(); err != nil {
   579  				log.Errorf("[Store][database] batch set instance health status commit tx err: %s", err.Error())
   580  				return err
   581  			}
   582  
   583  			return nil
   584  		})
   585  	})
   586  }
   587  
   588  // BatchSetInstanceIsolate 批量设置实例隔离状态
   589  func (ins *instanceStore) BatchSetInstanceIsolate(ids []interface{}, isolate int, revision string) error {
   590  	return RetryTransaction("batchSetInstanceIsolate", func() error {
   591  		return ins.master.processWithTransaction("batchSetInstanceIsolate", func(tx *BaseTx) error {
   592  			if err := BatchOperation("set-instance-isolate", ids, func(objects []interface{}) error {
   593  				if len(objects) == 0 {
   594  					return nil
   595  				}
   596  				str := "update instance set isolate = ?, revision = ?, mtime = sysdate() where id in "
   597  				str += "(" + PlaceholdersN(len(objects)) + ")"
   598  				args := make([]interface{}, 0, len(objects)+2)
   599  				args = append(args, isolate)
   600  				args = append(args, revision)
   601  				args = append(args, objects...)
   602  				_, err := tx.Exec(str, args...)
   603  				return store.Error(err)
   604  			}); err != nil {
   605  				return err
   606  			}
   607  
   608  			if err := tx.Commit(); err != nil {
   609  				log.Errorf("[Store][database] batch set instance isolate commit tx err: %s", err.Error())
   610  				return err
   611  			}
   612  
   613  			return nil
   614  		})
   615  	})
   616  }
   617  
   618  // BatchAppendInstanceMetadata 追加实例 metadata
   619  func (ins *instanceStore) BatchAppendInstanceMetadata(requests []*store.InstanceMetadataRequest) error {
   620  	if len(requests) == 0 {
   621  		return nil
   622  	}
   623  	return ins.master.processWithTransaction("AppendInstanceMetadata", func(tx *BaseTx) error {
   624  		for i := range requests {
   625  			id := requests[i].InstanceID
   626  			revision := requests[i].Revision
   627  			metadata := requests[i].Metadata
   628  			str := "replace into instance_metadata(`id`, `mkey`, `mvalue`, `ctime`, `mtime`) values"
   629  			values := make([]string, 0, len(metadata))
   630  			args := make([]interface{}, 0, len(metadata)*3)
   631  			for k, v := range metadata {
   632  				values = append(values, "(?, ?, ?, sysdate(), sysdate())")
   633  				args = append(args, id, k, v)
   634  			}
   635  			str += strings.Join(values, ",")
   636  			if log.DebugEnabled() {
   637  				log.Debug("[Store][database] append instance metadata", zap.String("sql", str), zap.Any("args", args))
   638  			}
   639  			if _, err := tx.Exec(str, args...); err != nil {
   640  				log.Errorf("[Store][database] append instance metadata err: %s", err.Error())
   641  				return err
   642  			}
   643  
   644  			str = "update instance set revision = ?, mtime = sysdate() where id = ?"
   645  			if _, err := tx.Exec(str, revision, id); err != nil {
   646  				log.Errorf("[Store][database] append instance metadata update revision err: %s", err.Error())
   647  				return err
   648  			}
   649  		}
   650  		return tx.Commit()
   651  	})
   652  }
   653  
   654  // BatchRemoveInstanceMetadata 删除实例指定的 metadata
   655  func (ins *instanceStore) BatchRemoveInstanceMetadata(requests []*store.InstanceMetadataRequest) error {
   656  	if len(requests) == 0 {
   657  		return nil
   658  	}
   659  	return ins.master.processWithTransaction("RemoveInstanceMetadata", func(tx *BaseTx) error {
   660  		for i := range requests {
   661  			id := requests[i].InstanceID
   662  			revision := requests[i].Revision
   663  			keys := requests[i].Keys
   664  			str := "delete from instance_metadata where id = ? and mkey in (%s)"
   665  			values := make([]string, 0, len(keys))
   666  			args := make([]interface{}, 0, 1+len(keys))
   667  			args = append(args, id)
   668  			for i := range keys {
   669  				key := keys[i]
   670  				values = append(values, "?")
   671  				args = append(args, key)
   672  			}
   673  			str = fmt.Sprintf(str, strings.Join(values, ","))
   674  
   675  			if _, err := tx.Exec(str, args...); err != nil {
   676  				log.Errorf("[Store][database] remove instance metadata by keys err: %s", err.Error())
   677  				return err
   678  			}
   679  
   680  			str = "update instance set revision = ?, mtime = sysdate() where id = ?"
   681  			if _, err := tx.Exec(str, revision, id); err != nil {
   682  				log.Errorf("[Store][database] remove instance metadata by keys update revision err: %s", err.Error())
   683  				return err
   684  			}
   685  		}
   686  		return tx.Commit()
   687  	})
   688  }
   689  
   690  // getInstance 内部获取instance函数,根据instanceID,直接读取元数据,不做其他过滤
   691  func (ins *instanceStore) getInstance(instanceID string) (*model.Instance, error) {
   692  	str := genInstanceSelectSQL() + " where instance.id = ?"
   693  	rows, err := ins.master.Query(str, instanceID)
   694  	if err != nil {
   695  		log.Errorf("[Store][database] get instance query err: %s", err.Error())
   696  		return nil, err
   697  	}
   698  
   699  	out, err := fetchInstanceRows(rows)
   700  	if err != nil {
   701  		return nil, err
   702  	}
   703  
   704  	if len(out) == 0 {
   705  		return nil, err
   706  	}
   707  
   708  	meta, err := ins.GetInstanceMeta(out[0].ID())
   709  	if err != nil {
   710  		return nil, err
   711  	}
   712  	out[0].MallocProto()
   713  	out[0].Proto.Metadata = meta
   714  
   715  	return out[0], nil
   716  }
   717  
   718  // getMoreInstancesMainWithMeta 获取增量instance+healthcheck+meta内容
   719  // @note ro库有多个实例,且主库到ro库各实例的同步时间不一致。为避免获取不到meta,需要采用一条sql语句获取全部数据
   720  func (ins *instanceStore) getMoreInstancesMainWithMeta(tx *BaseTx, mtime time.Time, firstUpdate bool, serviceID []string) (
   721  	map[string]*model.Instance, error) {
   722  	// 首次拉取
   723  	if firstUpdate {
   724  		// 获取全量服务实例
   725  		instances, err := ins.getMoreInstancesMain(tx, mtime, firstUpdate, serviceID)
   726  		if err != nil {
   727  			log.Errorf("[Store][database] get more instance main err: %s", err.Error())
   728  			return nil, err
   729  		}
   730  		// 获取全量服务实例元数据
   731  		str := "select id, mkey, mvalue from instance_metadata"
   732  		rows, err := tx.Query(str)
   733  		if err != nil {
   734  			log.Errorf("[Store][database] acquire instances meta query err: %s", err.Error())
   735  			return nil, err
   736  		}
   737  		if err := fetchInstanceMetaRows(instances, rows); err != nil {
   738  			return nil, err
   739  		}
   740  		return instances, nil
   741  	}
   742  
   743  	// 非首次拉取
   744  	str := genCompleteInstanceSelectSQL() + " where instance.mtime >= FROM_UNIXTIME(?)"
   745  	args := make([]interface{}, 0, len(serviceID)+1)
   746  	args = append(args, timeToTimestamp(mtime))
   747  
   748  	if len(serviceID) > 0 {
   749  		str += " and service_id in (" + PlaceholdersN(len(serviceID))
   750  		str += ")"
   751  	}
   752  	for _, id := range serviceID {
   753  		args = append(args, id)
   754  	}
   755  
   756  	rows, err := ins.slave.Query(str, args...)
   757  	if err != nil {
   758  		log.Errorf("[Store][database] get more instance query err: %s", err.Error())
   759  		return nil, err
   760  	}
   761  	return fetchInstanceWithMetaRows(rows)
   762  }
   763  
   764  // fetchInstanceWithMetaRows 获取instance main+health_check+instance_metadata rows里面的数据
   765  func fetchInstanceWithMetaRows(rows *sql.Rows) (map[string]*model.Instance, error) {
   766  	if rows == nil {
   767  		return nil, nil
   768  	}
   769  	defer rows.Close()
   770  
   771  	out := make(map[string]*model.Instance)
   772  	var item model.InstanceStore
   773  	var id, mKey, mValue string
   774  	progress := 0
   775  	for rows.Next() {
   776  		progress++
   777  		if progress%100000 == 0 {
   778  			log.Infof("[Store][database] instance+meta fetch rows progress: %d", progress)
   779  		}
   780  		if err := rows.Scan(&item.ID, &item.ServiceID, &item.VpcID, &item.Host, &item.Port, &item.Protocol,
   781  			&item.Version, &item.HealthStatus, &item.Isolate, &item.Weight, &item.EnableHealthCheck,
   782  			&item.LogicSet, &item.Region, &item.Zone, &item.Campus, &item.Priority, &item.Revision,
   783  			&item.Flag, &item.CheckType, &item.TTL, &id, &mKey, &mValue,
   784  			&item.CreateTime, &item.ModifyTime); err != nil {
   785  			log.Errorf("[Store][database] fetch instance+meta rows err: %s", err.Error())
   786  			return nil, err
   787  		}
   788  
   789  		if _, ok := out[item.ID]; !ok {
   790  			out[item.ID] = model.Store2Instance(&item)
   791  		}
   792  		// 实例存在meta
   793  		if id != "" {
   794  			if out[item.ID].Proto.Metadata == nil {
   795  				out[item.ID].Proto.Metadata = make(map[string]string)
   796  			}
   797  			out[item.ID].Proto.Metadata[mKey] = mValue
   798  		}
   799  	}
   800  	if err := rows.Err(); err != nil {
   801  		log.Errorf("[Store][database] fetch instance+metadata rows next err: %s", err.Error())
   802  		return nil, err
   803  	}
   804  	return out, nil
   805  }
   806  
   807  // getMoreInstancesMain 获取增量instances 主表内容,health_check内容
   808  func (ins *instanceStore) getMoreInstancesMain(tx *BaseTx, mtime time.Time, firstUpdate bool,
   809  	serviceID []string) (map[string]*model.Instance, error) {
   810  
   811  	str := genInstanceSelectSQL() + " where instance.mtime >= FROM_UNIXTIME(?)"
   812  	args := make([]interface{}, 0, len(serviceID)+1)
   813  	args = append(args, timeToTimestamp(mtime))
   814  
   815  	if firstUpdate {
   816  		str += " and flag != 1"
   817  	}
   818  
   819  	if len(serviceID) > 0 {
   820  		str += " and service_id in (" + PlaceholdersN(len(serviceID))
   821  		str += ")"
   822  	}
   823  	for _, id := range serviceID {
   824  		args = append(args, id)
   825  	}
   826  
   827  	rows, err := tx.Query(str, args...)
   828  	if err != nil {
   829  		log.Errorf("[Store][database] get more instance query err: %s", err.Error())
   830  		return nil, err
   831  	}
   832  
   833  	out := make(map[string]*model.Instance)
   834  	err = callFetchInstanceRows(rows, func(entry *model.InstanceStore) (b bool, e error) {
   835  		out[entry.ID] = model.Store2Instance(entry)
   836  		return true, nil
   837  	})
   838  	if err != nil {
   839  		log.Errorf("[Store][database] call fetch instance rows err: %s", err.Error())
   840  		return nil, err
   841  	}
   842  
   843  	return out, nil
   844  }
   845  
   846  // getRowExpandInstances 根据rows获取对应expandInstance
   847  func (ins *instanceStore) getRowExpandInstances(rows *sql.Rows) ([]*model.Instance, error) {
   848  	out, err := fetchExpandInstanceRows(rows)
   849  	if err != nil {
   850  		return nil, err
   851  	}
   852  
   853  	data := make([]interface{}, 0, len(out))
   854  	for idx := range out {
   855  		data = append(data, out[idx].Proto)
   856  	}
   857  
   858  	err = BatchQuery("expand-instance-metadata", data, func(objects []interface{}) error {
   859  		return ins.batchAcquireInstanceMetadata(objects)
   860  	})
   861  	if err != nil {
   862  		log.Errorf("[Store][database] get expand instances metadata err: %s", err.Error())
   863  		return nil, err
   864  	}
   865  
   866  	return out, nil
   867  }
   868  
   869  // batchAcquireInstanceMetadata 批量获取instance的metadata信息
   870  // web端获取实例的数据的时候使用
   871  func (ins *instanceStore) batchAcquireInstanceMetadata(instances []interface{}) error {
   872  	rows, err := batchQueryMetadata(ins.master.Query, instances)
   873  	if err != nil {
   874  		return err
   875  	}
   876  	if rows == nil {
   877  		return nil
   878  	}
   879  	defer rows.Close()
   880  
   881  	out := make(map[string]map[string]string)
   882  	var id, key, value string
   883  	for rows.Next() {
   884  		if err := rows.Scan(&id, &key, &value); err != nil {
   885  			log.Errorf("[Store][database] multi query instance metadata rows scan err: %s", err.Error())
   886  			return err
   887  		}
   888  		if _, ok := out[id]; !ok {
   889  			out[id] = make(map[string]string)
   890  		}
   891  		out[id][key] = value
   892  	}
   893  	if err := rows.Err(); err != nil {
   894  		log.Errorf("[Store][database] multi query instance metadata rows next err: %s", err.Error())
   895  		return err
   896  	}
   897  
   898  	// 把接收到的metadata,设置到instance中
   899  	// 这里会有两层循环,后续可以优化 TODO
   900  	for id, meta := range out {
   901  		for _, ele := range instances {
   902  			if id == ele.(*apiservice.Instance).GetId().GetValue() {
   903  				ele.(*apiservice.Instance).Metadata = meta
   904  				break
   905  			}
   906  		}
   907  	}
   908  
   909  	return nil
   910  }
   911  
   912  // batchQueryMetadata 批量查找metadata
   913  func batchQueryMetadata(queryHandler QueryHandler, instances []interface{}) (*sql.Rows, error) {
   914  	if len(instances) == 0 {
   915  		return nil, nil
   916  	}
   917  
   918  	str := "select `id`, `mkey`, `mvalue` from instance_metadata where id in("
   919  	first := true
   920  	args := make([]interface{}, 0, len(instances))
   921  	for _, ele := range instances {
   922  		if first {
   923  			str += "?"
   924  			first = false
   925  		} else {
   926  			str += ",?"
   927  		}
   928  		args = append(args, ele.(*apiservice.Instance).GetId().GetValue())
   929  	}
   930  	str += ")"
   931  
   932  	rows, err := queryHandler(str, args...)
   933  	if err != nil {
   934  		log.Errorf("[Store][database] multi query instance metadata err: %s", err.Error())
   935  		return nil, err
   936  	}
   937  
   938  	return rows, nil
   939  }
   940  
   941  // addMainInstance 往instance主表中增加数据
   942  func addMainInstance(tx *BaseTx, instance *model.Instance) error {
   943  	// #lizard forgives
   944  	str := `replace into instance(id, service_id, vpc_id, host, port, protocol, version, health_status, isolate,
   945  		 weight, enable_health_check, logic_set, cmdb_region, cmdb_zone, cmdb_idc, priority, revision, ctime, mtime)
   946  			 values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, sysdate(), sysdate())`
   947  	_, err := tx.Exec(str, instance.ID(), instance.ServiceID, instance.VpcID(), instance.Host(), instance.Port(),
   948  		instance.Protocol(), instance.Version(), instance.Healthy(), instance.Isolate(), instance.Weight(),
   949  		instance.EnableHealthCheck(), instance.LogicSet(), instance.Location().GetRegion().GetValue(),
   950  		instance.Location().GetZone().GetValue(), instance.Location().GetCampus().GetValue(),
   951  		instance.Priority(), instance.Revision())
   952  	return err
   953  }
   954  
   955  // batchAddMainInstances 批量增加main instance数据
   956  func batchAddMainInstances(tx *BaseTx, instances []*model.Instance) error {
   957  	str := `replace into instance(id, service_id, vpc_id, host, port, protocol, version, health_status, isolate,
   958  		 weight, enable_health_check, logic_set, cmdb_region, cmdb_zone, cmdb_idc, priority, revision, ctime, mtime) 
   959  		 values`
   960  	first := true
   961  	args := make([]interface{}, 0)
   962  	for _, entry := range instances {
   963  		if !first {
   964  			str += ","
   965  		}
   966  		str += "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, sysdate(), sysdate())"
   967  		first = false
   968  		args = append(args, entry.ID(), entry.ServiceID, entry.VpcID(), entry.Host(), entry.Port())
   969  		args = append(args, entry.Protocol(), entry.Version(), entry.Healthy(), entry.Isolate(),
   970  			entry.Weight())
   971  		args = append(args, entry.EnableHealthCheck(), entry.LogicSet(),
   972  			entry.Location().GetRegion().GetValue(), entry.Location().GetZone().GetValue(),
   973  			entry.Location().GetCampus().GetValue(), entry.Priority(), entry.Revision())
   974  	}
   975  	_, err := tx.Exec(str, args...)
   976  	return err
   977  }
   978  
   979  // addInstanceCheck 往health_check加入健康检查信息
   980  func addInstanceCheck(tx *BaseTx, instance *model.Instance) error {
   981  	check := instance.HealthCheck()
   982  	if check == nil {
   983  		return nil
   984  	}
   985  
   986  	str := "replace into health_check(`id`, `type`, `ttl`) values(?, ?, ?)"
   987  	_, err := tx.Exec(str, instance.ID(), check.GetType(),
   988  		check.GetHeartbeat().GetTtl().GetValue())
   989  	return err
   990  }
   991  
   992  // batchAddInstanceCheck 批量增加healthCheck数据
   993  func batchAddInstanceCheck(tx *BaseTx, instances []*model.Instance) error {
   994  	str := "replace into health_check(`id`, `type`, `ttl`) values"
   995  	first := true
   996  	args := make([]interface{}, 0)
   997  	for _, entry := range instances {
   998  		if entry.HealthCheck() == nil {
   999  			continue
  1000  		}
  1001  		if !first {
  1002  			str += ","
  1003  		}
  1004  		str += "(?,?,?)"
  1005  		first = false
  1006  		args = append(args, entry.ID(), entry.HealthCheck().GetType(),
  1007  			entry.HealthCheck().GetHeartbeat().GetTtl().GetValue())
  1008  	}
  1009  	// 不存在健康检查信息,直接返回
  1010  	if first {
  1011  		return nil
  1012  	}
  1013  	_, err := tx.Exec(str, args...)
  1014  	return err
  1015  }
  1016  
  1017  // addInstanceMeta 往表中加入instance meta数据
  1018  func addInstanceMeta(tx *BaseTx, id string, meta map[string]string) error {
  1019  	if len(meta) == 0 {
  1020  		return nil
  1021  	}
  1022  
  1023  	str := "insert into instance_metadata(`id`, `mkey`, `mvalue`, `ctime`, `mtime`) values "
  1024  	args := make([]interface{}, 0, len(meta)*3)
  1025  	cnt := 0
  1026  	for key, value := range meta {
  1027  		cnt++
  1028  		if cnt == len(meta) {
  1029  			str += "(?, ?, ?, sysdate(), sysdate())"
  1030  		} else {
  1031  			str += "(?, ?, ?, sysdate(), sysdate()), "
  1032  		}
  1033  
  1034  		args = append(args, id)
  1035  		args = append(args, key)
  1036  		args = append(args, value)
  1037  	}
  1038  
  1039  	_, err := tx.Exec(str, args...)
  1040  	return err
  1041  }
  1042  
  1043  // batchDeleteInstanceMeta 批量删除metadata数据
  1044  func batchDeleteInstanceMeta(tx *BaseTx, instances []*model.Instance) error {
  1045  	ids := make([]interface{}, 0, len(instances))
  1046  	builder := strings.Builder{}
  1047  	for _, entry := range instances {
  1048  		// If instance is first registration, no need to participate in the following METADATA cleaning action
  1049  		// if entry.FirstRegis {
  1050  		// 	continue
  1051  		// }
  1052  
  1053  		ids = append(ids, entry.ID())
  1054  
  1055  		if len(ids) > 1 {
  1056  			builder.WriteString(",")
  1057  		}
  1058  		builder.WriteString("?")
  1059  	}
  1060  
  1061  	if len(ids) == 0 {
  1062  		return nil
  1063  	}
  1064  
  1065  	str := `delete from instance_metadata where id in (` + builder.String() + `)`
  1066  	_, err := tx.Exec(str, ids...)
  1067  	return err
  1068  }
  1069  
  1070  // batchAddInstanceMeta 批量增加metadata数据
  1071  func batchAddInstanceMeta(tx *BaseTx, instances []*model.Instance) error {
  1072  	str := "insert into instance_metadata(`id`, `mkey`, `mvalue`, `ctime`, `mtime`) values"
  1073  	args := make([]interface{}, 0)
  1074  	first := true
  1075  	for _, entry := range instances {
  1076  		if entry.Metadata() == nil || len(entry.Metadata()) == 0 {
  1077  			continue
  1078  		}
  1079  
  1080  		for key, value := range entry.Metadata() {
  1081  			if !first {
  1082  				str += ","
  1083  			}
  1084  			str += "(?, ?, ?, sysdate(), sysdate())"
  1085  			first = false
  1086  			args = append(args, entry.ID(), key, value)
  1087  		}
  1088  	}
  1089  	// 不存在metadata,直接返回
  1090  	if first {
  1091  		return nil
  1092  	}
  1093  
  1094  	_, err := tx.Exec(str, args...)
  1095  	return err
  1096  }
  1097  
  1098  // updateInstanceMeta 更新instance的meta表
  1099  func updateInstanceMeta(tx *BaseTx, instance *model.Instance) error {
  1100  	// 只有metadata为nil的时候,则不用处理。
  1101  	// 如果metadata不为nil,但是len(metadata) == 0,则代表删除metadata
  1102  	meta := instance.Metadata()
  1103  	if meta == nil {
  1104  		return nil
  1105  	}
  1106  
  1107  	deleteStr := "delete from instance_metadata where id = ?"
  1108  	if _, err := tx.Exec(deleteStr, instance.ID()); err != nil {
  1109  		return err
  1110  	}
  1111  	return addInstanceMeta(tx, instance.ID(), meta)
  1112  }
  1113  
  1114  // updateInstanceCheck 更新instance的check表
  1115  func updateInstanceCheck(tx *BaseTx, instance *model.Instance) error {
  1116  	// healthCheck为空,则删除
  1117  	check := instance.HealthCheck()
  1118  	if check == nil {
  1119  		return deleteInstanceCheck(tx, instance.ID())
  1120  	}
  1121  
  1122  	str := "replace into health_check(id, type, ttl) values(?, ?, ?)"
  1123  	_, err := tx.Exec(str, instance.ID(), check.GetType(),
  1124  		check.GetHeartbeat().GetTtl().GetValue())
  1125  	return err
  1126  }
  1127  
  1128  // updateInstanceMain 更新instance主表
  1129  func updateInstanceMain(tx *BaseTx, instance *model.Instance) error {
  1130  	str := `update instance set protocol = ?,
  1131  	 version = ?, health_status = ?, isolate = ?, weight = ?, enable_health_check = ?, logic_set = ?,
  1132  	 cmdb_region = ?, cmdb_zone = ?, cmdb_idc = ?, priority = ?, revision = ?, mtime = sysdate() where id = ?`
  1133  
  1134  	_, err := tx.Exec(str, instance.Protocol(), instance.Version(), instance.Healthy(), instance.Isolate(),
  1135  		instance.Weight(), instance.EnableHealthCheck(), instance.LogicSet(),
  1136  		instance.Location().GetRegion().GetValue(), instance.Location().GetZone().GetValue(),
  1137  		instance.Location().GetCampus().GetValue(), instance.Priority(),
  1138  		instance.Revision(), instance.ID())
  1139  
  1140  	return err
  1141  }
  1142  
  1143  // deleteInstanceCheck 删除healthCheck数据
  1144  func deleteInstanceCheck(tx *BaseTx, id string) error {
  1145  	str := "delete from health_check where id = ?"
  1146  	_, err := tx.Exec(str, id)
  1147  	return err
  1148  }
  1149  
  1150  // fetchInstanceRows 获取instance rows的内容
  1151  func fetchInstanceRows(rows *sql.Rows) ([]*model.Instance, error) {
  1152  	var out []*model.Instance
  1153  	err := callFetchInstanceRows(rows, func(entry *model.InstanceStore) (b bool, e error) {
  1154  		out = append(out, model.Store2Instance(entry))
  1155  		return true, nil
  1156  	})
  1157  	if err != nil {
  1158  		log.Errorf("[Store][database] call fetch instance rows err: %s", err.Error())
  1159  		return nil, err
  1160  	}
  1161  
  1162  	return out, nil
  1163  }
  1164  
  1165  // callFetchInstanceRows 带回调的fetch instance
  1166  func callFetchInstanceRows(rows *sql.Rows, callback func(entry *model.InstanceStore) (bool, error)) error {
  1167  	if rows == nil {
  1168  		return nil
  1169  	}
  1170  	defer rows.Close()
  1171  	var item model.InstanceStore
  1172  	progress := 0
  1173  	for rows.Next() {
  1174  		progress++
  1175  		if progress%100000 == 0 {
  1176  			log.Infof("[Store][database] instance fetch rows progress: %d", progress)
  1177  		}
  1178  		err := rows.Scan(&item.ID, &item.ServiceID, &item.VpcID, &item.Host, &item.Port, &item.Protocol,
  1179  			&item.Version, &item.HealthStatus, &item.Isolate, &item.Weight, &item.EnableHealthCheck,
  1180  			&item.LogicSet, &item.Region, &item.Zone, &item.Campus, &item.Priority, &item.Revision,
  1181  			&item.Flag, &item.CheckType, &item.TTL, &item.CreateTime, &item.ModifyTime)
  1182  		if err != nil {
  1183  			log.Errorf("[Store][database] fetch instance rows err: %s", err.Error())
  1184  			return err
  1185  		}
  1186  		ok, err := callback(&item)
  1187  		if err != nil {
  1188  			return err
  1189  		}
  1190  		if !ok {
  1191  			return nil
  1192  		}
  1193  	}
  1194  	if err := rows.Err(); err != nil {
  1195  		log.Errorf("[Store][database] instance rows catch err: %s", err.Error())
  1196  		return err
  1197  	}
  1198  
  1199  	return nil
  1200  }
  1201  
  1202  // fetchExpandInstanceRows 获取expandInstance rows的内容
  1203  func fetchExpandInstanceRows(rows *sql.Rows) ([]*model.Instance, error) {
  1204  	if rows == nil {
  1205  		return nil, nil
  1206  	}
  1207  	defer rows.Close()
  1208  
  1209  	var out []*model.Instance
  1210  	var item model.ExpandInstanceStore
  1211  	var instance model.InstanceStore
  1212  	item.ServiceInstance = &instance
  1213  	progress := 0
  1214  	for rows.Next() {
  1215  		progress++
  1216  		if progress%50000 == 0 {
  1217  			log.Infof("[Store][database] expand instance fetch rows progress: %d", progress)
  1218  		}
  1219  		err := rows.Scan(&instance.ID, &instance.ServiceID, &instance.VpcID, &instance.Host, &instance.Port,
  1220  			&instance.Protocol, &instance.Version, &instance.HealthStatus, &instance.Isolate,
  1221  			&instance.Weight, &instance.EnableHealthCheck, &instance.LogicSet, &instance.Region,
  1222  			&instance.Zone, &instance.Campus, &instance.Priority, &instance.Revision, &instance.Flag,
  1223  			&instance.CheckType, &instance.TTL, &item.ServiceName, &item.Namespace,
  1224  			&instance.CreateTime, &instance.ModifyTime)
  1225  		if err != nil {
  1226  			log.Errorf("[Store][database] fetch instance rows err: %s", err.Error())
  1227  			return nil, err
  1228  		}
  1229  		out = append(out, model.ExpandStore2Instance(&item))
  1230  	}
  1231  
  1232  	if err := rows.Err(); err != nil {
  1233  		log.Errorf("[Store][database] instance rows catch err: %s", err.Error())
  1234  		return nil, err
  1235  	}
  1236  
  1237  	return out, nil
  1238  }
  1239  
  1240  // fetchInstanceMetaRows 解析获取instance metadata
  1241  func fetchInstanceMetaRows(instances map[string]*model.Instance, rows *sql.Rows) error {
  1242  	if rows == nil {
  1243  		return nil
  1244  	}
  1245  	defer rows.Close()
  1246  	var id, key, value string
  1247  	progress := 0
  1248  	for rows.Next() {
  1249  		progress++
  1250  		if progress%500000 == 0 {
  1251  			log.Infof("[Store][database] fetch instance meta progress: %d", progress)
  1252  		}
  1253  		if err := rows.Scan(&id, &key, &value); err != nil {
  1254  			log.Errorf("[Store][database] fetch instance metadata rows scan err: %s", err.Error())
  1255  			return err
  1256  		}
  1257  		// 不在目标列表,不存储
  1258  		if _, ok := instances[id]; !ok {
  1259  			continue
  1260  		}
  1261  		if instances[id].Proto.Metadata == nil {
  1262  			instances[id].Proto.Metadata = make(map[string]string)
  1263  		}
  1264  		instances[id].Proto.Metadata[key] = value
  1265  	}
  1266  	if err := rows.Err(); err != nil {
  1267  		log.Errorf("[Store][database] fetch instance metadata rows next err: %s", err.Error())
  1268  		return err
  1269  	}
  1270  
  1271  	return nil
  1272  }
  1273  
  1274  // genInstanceSelectSQL 生成instance的select sql语句
  1275  func genInstanceSelectSQL() string {
  1276  	str := `select instance.id, service_id, IFNULL(vpc_id,""), host, port, IFNULL(protocol, ""), IFNULL(version, ""),
  1277  			 health_status, isolate, weight, enable_health_check, IFNULL(logic_set, ""), IFNULL(cmdb_region, ""), 
  1278  			 IFNULL(cmdb_zone, ""), IFNULL(cmdb_idc, ""), priority, revision, flag, IFNULL(health_check.type, -1), 
  1279  			 IFNULL(health_check.ttl, 0), UNIX_TIMESTAMP(instance.ctime), UNIX_TIMESTAMP(instance.mtime)   
  1280  			 from instance left join health_check 
  1281  			 on instance.id = health_check.id `
  1282  	return str
  1283  }
  1284  
  1285  // genCompleteInstanceSelectSQL 生成完整instance(主表+health_check+metadata)的sql语句
  1286  func genCompleteInstanceSelectSQL() string {
  1287  	str := `select instance.id, service_id, IFNULL(vpc_id,""), host, port, IFNULL(protocol, ""), IFNULL(version, ""),
  1288  		 health_status, isolate, weight, enable_health_check, IFNULL(logic_set, ""), IFNULL(cmdb_region, ""),
  1289  		 IFNULL(cmdb_zone, ""), IFNULL(cmdb_idc, ""), priority, revision, flag, IFNULL(health_check.type, -1),
  1290  		 IFNULL(health_check.ttl, 0), IFNULL(instance_metadata.id, ""), IFNULL(mkey, ""), IFNULL(mvalue, ""), 
  1291  		 UNIX_TIMESTAMP(instance.ctime), UNIX_TIMESTAMP(instance.mtime)
  1292  		 from instance 
  1293  		 left join health_check on instance.id = health_check.id 
  1294  		 left join instance_metadata on instance.id = instance_metadata.id `
  1295  	return str
  1296  }
  1297  
  1298  // genExpandInstanceSelectSQL 生成expandInstance的select sql语句
  1299  func genExpandInstanceSelectSQL(needForceIndex bool) string {
  1300  	str := `select instance.id, service_id, IFNULL(vpc_id,""), host, port, IFNULL(protocol, ""), IFNULL(version, ""),
  1301  					 health_status, isolate, weight, enable_health_check, IFNULL(logic_set, ""), IFNULL(cmdb_region, ""), 
  1302  					 IFNULL(cmdb_zone, ""), IFNULL(cmdb_idc, ""), priority, instance.revision, instance.flag, 
  1303  					 IFNULL(health_check.type, -1), IFNULL(health_check.ttl, 0), service.name, service.namespace, 
  1304  					 UNIX_TIMESTAMP(instance.ctime), UNIX_TIMESTAMP(instance.mtime) 
  1305  					 from (service inner join instance `
  1306  	if needForceIndex {
  1307  		str += `force index(service_id, host) `
  1308  	}
  1309  	str += `on service.id = instance.service_id) left join health_check on instance.id = health_check.id `
  1310  	return str
  1311  }