github.com/polarismesh/polaris@v1.17.8/store/boltdb/config_file_release.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  	"time"
    23  
    24  	bolt "go.etcd.io/bbolt"
    25  	"go.uber.org/zap"
    26  
    27  	"github.com/polarismesh/polaris/common/model"
    28  	"github.com/polarismesh/polaris/store"
    29  )
    30  
    31  var _ store.ConfigFileReleaseStore = (*configFileReleaseStore)(nil)
    32  
    33  const (
    34  	tblConfigFileRelease string = "ConfigFileRelease"
    35  
    36  	FileReleaseFieldId         string = "Id"
    37  	FileReleaseFieldName       string = "Name"
    38  	FileReleaseFieldNamespace  string = "Namespace"
    39  	FileReleaseFieldGroup      string = "Group"
    40  	FileReleaseFieldFileName   string = "FileName"
    41  	FileReleaseFieldContent    string = "Content"
    42  	FileReleaseFieldComment    string = "Comment"
    43  	FileReleaseFieldMd5        string = "Md5"
    44  	FileReleaseFieldVersion    string = "Version"
    45  	FileReleaseFieldFlag       string = "Flag"
    46  	FileReleaseFieldCreateTime string = "CreateTime"
    47  	FileReleaseFieldCreateBy   string = "CreateBy"
    48  	FileReleaseFieldModifyTime string = "ModifyTime"
    49  	FileReleaseFieldModifyBy   string = "ModifyBy"
    50  	FileReleaseFieldValid      string = "Valid"
    51  	FileReleaseFieldActive     string = "Active"
    52  	FileReleaseFieldMetadata   string = "Metadata"
    53  )
    54  
    55  var (
    56  	ErrMultipleConfigFileReleaseFound error = errors.New("multiple config_file_release found")
    57  )
    58  
    59  type configFileReleaseStore struct {
    60  	handler BoltHandler
    61  }
    62  
    63  func newConfigFileReleaseStore(handler BoltHandler) *configFileReleaseStore {
    64  	s := &configFileReleaseStore{handler: handler}
    65  	return s
    66  }
    67  
    68  // CreateConfigFileReleaseTx 新建配置文件发布
    69  func (cfr *configFileReleaseStore) CreateConfigFileReleaseTx(proxyTx store.Tx,
    70  	fileRelease *model.ConfigFileRelease) error {
    71  	tx := proxyTx.GetDelegateTx().(*bolt.Tx)
    72  	// 是否存在当前 release
    73  	values := map[string]interface{}{}
    74  	if err := loadValues(tx, tblConfigFileRelease, []string{fileRelease.ReleaseKey()},
    75  		&ConfigFileRelease{}, values); err != nil {
    76  		return err
    77  	}
    78  	if len(values) != 0 {
    79  		return store.NewStatusError(store.DuplicateEntryErr, "exist record")
    80  	}
    81  
    82  	table, err := tx.CreateBucketIfNotExists([]byte(tblConfigFileRelease))
    83  	if err != nil {
    84  		return store.Error(err)
    85  	}
    86  	nextId, err := table.NextSequence()
    87  	if err != nil {
    88  		return store.Error(err)
    89  	}
    90  	fileRelease.Id = nextId
    91  	fileRelease.Valid = true
    92  	tN := time.Now()
    93  	fileRelease.CreateTime = tN
    94  	fileRelease.ModifyTime = tN
    95  
    96  	maxVersion, err := cfr.inactiveConfigFileRelease(tx, fileRelease)
    97  	if err != nil {
    98  		return store.Error(err)
    99  	}
   100  
   101  	fileRelease.Active = true
   102  	fileRelease.Version = maxVersion + 1
   103  	err = saveValue(tx, tblConfigFileRelease, fileRelease.ReleaseKey(), cfr.toStoreData(fileRelease))
   104  	if err != nil {
   105  		log.Error("[ConfigFileRelease] save info", zap.Error(err))
   106  		return store.Error(err)
   107  	}
   108  	return nil
   109  }
   110  
   111  // GetConfigFileRelease Get the configuration file release, only the record of FLAG = 0
   112  func (cfr *configFileReleaseStore) GetConfigFileRelease(args *model.ConfigFileReleaseKey) (*model.ConfigFileRelease, error) {
   113  
   114  	values, err := cfr.handler.LoadValues(tblConfigFileRelease, []string{args.ReleaseKey()},
   115  		&ConfigFileRelease{})
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	for _, v := range values {
   120  		return cfr.toModelData(v.(*ConfigFileRelease)), nil
   121  	}
   122  	return nil, nil
   123  }
   124  
   125  // GetConfigFileRelease Get the configuration file release, only the record of FLAG = 0
   126  func (cfr *configFileReleaseStore) GetConfigFileReleaseTx(tx store.Tx,
   127  	args *model.ConfigFileReleaseKey) (*model.ConfigFileRelease, error) {
   128  	dbTx := tx.GetDelegateTx().(*bolt.Tx)
   129  	values := make(map[string]interface{}, 1)
   130  	err := loadValues(dbTx, tblConfigFileRelease, []string{args.ReleaseKey()},
   131  		&ConfigFileRelease{}, values)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	for _, v := range values {
   136  		return cfr.toModelData(v.(*ConfigFileRelease)), nil
   137  	}
   138  	return nil, nil
   139  }
   140  
   141  // GetConfigFileActiveRelease .
   142  func (cfr *configFileReleaseStore) GetConfigFileActiveRelease(file *model.ConfigFileKey) (*model.ConfigFileRelease, error) {
   143  	tx, err := cfr.handler.StartTx()
   144  	if err != nil {
   145  		return nil, store.Error(err)
   146  	}
   147  	defer func() {
   148  		_ = tx.Rollback()
   149  	}()
   150  	return cfr.GetConfigFileActiveReleaseTx(tx, file)
   151  }
   152  
   153  func (cfr *configFileReleaseStore) GetConfigFileActiveReleaseTx(tx store.Tx,
   154  	file *model.ConfigFileKey) (*model.ConfigFileRelease, error) {
   155  	dbTx := tx.GetDelegateTx().(*bolt.Tx)
   156  
   157  	fields := []string{FileReleaseFieldActive, FileReleaseFieldNamespace, FileReleaseFieldGroup,
   158  		FileReleaseFieldFileName, FileReleaseFieldValid}
   159  	values := make(map[string]interface{}, 1)
   160  	err := loadValuesByFilter(dbTx, tblConfigFileRelease, fields, &ConfigFileRelease{},
   161  		func(m map[string]interface{}) bool {
   162  			valid, _ := m[FileReleaseFieldValid].(bool)
   163  			// 已经删除的不管
   164  			if !valid {
   165  				return false
   166  			}
   167  			active, _ := m[FileReleaseFieldActive].(bool)
   168  			if !active {
   169  				return false
   170  			}
   171  			saveNs, _ := m[FileReleaseFieldNamespace].(string)
   172  			saveGroup, _ := m[FileReleaseFieldGroup].(string)
   173  			saveFileName, _ := m[FileReleaseFieldFileName].(string)
   174  
   175  			expect := saveNs == file.Namespace && saveGroup == file.Group && saveFileName == file.Name
   176  			return expect
   177  		}, values)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	for _, v := range values {
   182  		return cfr.toModelData(v.(*ConfigFileRelease)), nil
   183  	}
   184  	return nil, nil
   185  }
   186  
   187  // DeleteConfigFileRelease Delete the release data
   188  func (cfr *configFileReleaseStore) DeleteConfigFileReleaseTx(tx store.Tx, data *model.ConfigFileReleaseKey) error {
   189  	dbTx := tx.GetDelegateTx().(*bolt.Tx)
   190  	properties := make(map[string]interface{})
   191  
   192  	properties[FileReleaseFieldValid] = false
   193  	properties[FileReleaseFieldFlag] = 1
   194  	properties[FileReleaseFieldModifyTime] = time.Now()
   195  	if err := updateValue(dbTx, tblConfigFileRelease, data.ReleaseKey(), properties); err != nil {
   196  		log.Error("[ConfigFileRelease] delete info", zap.Error(err))
   197  		return store.Error(err)
   198  	}
   199  	return nil
   200  }
   201  
   202  // CountConfigReleases count the release data
   203  func (cfr *configFileReleaseStore) CountConfigReleases(namespace, group string, onlyActive bool) (uint64, error) {
   204  	fields := []string{FileReleaseFieldNamespace, FileReleaseFieldGroup, FileReleaseFieldValid, FileReleaseFieldActive}
   205  	ret, err := cfr.handler.LoadValuesByFilter(tblConfigFileRelease, fields, &ConfigFileRelease{},
   206  		func(m map[string]interface{}) bool {
   207  			valid, _ := m[FileReleaseFieldValid].(bool)
   208  			if !valid {
   209  				return false
   210  			}
   211  			if onlyActive {
   212  				active, _ := m[FileReleaseFieldActive].(bool)
   213  				if !active {
   214  					return false
   215  				}
   216  			}
   217  			saveNs, _ := m[FileReleaseFieldNamespace].(string)
   218  			saveGroup, _ := m[FileReleaseFieldNamespace].(string)
   219  			return saveNs == namespace && saveGroup == group
   220  		})
   221  	if err != nil {
   222  		return 0, err
   223  	}
   224  	return uint64(len(ret)), err
   225  }
   226  
   227  // CleanConfigFileReleasesTx
   228  func (cfr *configFileReleaseStore) CleanConfigFileReleasesTx(tx store.Tx, namespace, group, fileName string) error {
   229  	dbTx := tx.GetDelegateTx().(*bolt.Tx)
   230  
   231  	fields := []string{FileReleaseFieldNamespace, FileReleaseFieldGroup, FileReleaseFieldFileName,
   232  		FileReleaseFieldValid}
   233  	values := map[string]interface{}{}
   234  	err := loadValuesByFilter(dbTx, tblConfigFileRelease, fields, &ConfigFileRelease{},
   235  		func(m map[string]interface{}) bool {
   236  			flag, _ := m[FileReleaseFieldValid].(int)
   237  			// 已经删除的不管
   238  			if flag == 1 {
   239  				return false
   240  			}
   241  			saveNs, _ := m[FileReleaseFieldNamespace].(string)
   242  			saveGroup, _ := m[FileReleaseFieldGroup].(string)
   243  			saveFileName, _ := m[FileReleaseFieldFileName].(string)
   244  
   245  			expect := saveNs == namespace && saveGroup == group && saveFileName == fileName
   246  			return expect
   247  		}, values)
   248  
   249  	properties := map[string]interface{}{
   250  		FileReleaseFieldFlag:       1,
   251  		FileReleaseFieldValid:      false,
   252  		FileReleaseFieldModifyTime: time.Now(),
   253  	}
   254  	for key := range values {
   255  		if err := updateValue(dbTx, tblConfigFileRelease, key, properties); err != nil {
   256  			return nil
   257  		}
   258  	}
   259  
   260  	return err
   261  }
   262  
   263  // GetMoreReleaseFile Get the last update time more than a certain time point
   264  // pay attention to containing Flag = 1, in order to get the deleted Release
   265  func (cfr *configFileReleaseStore) GetMoreReleaseFile(firstUpdate bool,
   266  	modifyTime time.Time) ([]*model.ConfigFileRelease, error) {
   267  
   268  	if firstUpdate {
   269  		modifyTime = time.Time{}
   270  	}
   271  
   272  	fields := []string{FileReleaseFieldModifyTime}
   273  	ret, err := cfr.handler.LoadValuesByFilter(tblConfigFileRelease, fields, &ConfigFileRelease{},
   274  		func(m map[string]interface{}) bool {
   275  			saveMt, _ := m[FileReleaseFieldModifyTime].(time.Time)
   276  			return !saveMt.Before(modifyTime)
   277  		})
   278  
   279  	if err != nil {
   280  		return nil, err
   281  	}
   282  
   283  	releases := make([]*model.ConfigFileRelease, 0, len(ret))
   284  	for _, v := range ret {
   285  		releases = append(releases, cfr.toModelData(v.(*ConfigFileRelease)))
   286  	}
   287  	return releases, nil
   288  }
   289  
   290  func (cfr *configFileReleaseStore) ActiveConfigFileReleaseTx(tx store.Tx, release *model.ConfigFileRelease) error {
   291  	dbTx := tx.GetDelegateTx().(*bolt.Tx)
   292  	maxVersion, err := cfr.inactiveConfigFileRelease(dbTx, release)
   293  	if err != nil {
   294  		return err
   295  	}
   296  	properties := make(map[string]interface{})
   297  	properties[FileReleaseFieldVersion] = maxVersion + 1
   298  	properties[FileReleaseFieldActive] = true
   299  	properties[FileReleaseFieldModifyTime] = time.Now()
   300  	return updateValue(dbTx, tblConfigFileRelease, release.ReleaseKey(), properties)
   301  }
   302  
   303  func (cfr *configFileReleaseStore) inactiveConfigFileRelease(tx *bolt.Tx,
   304  	release *model.ConfigFileRelease) (uint64, error) {
   305  
   306  	fields := []string{FileReleaseFieldNamespace, FileReleaseFieldGroup, FileReleaseFieldFileName,
   307  		FileReleaseFieldVersion, FileReleaseFieldFlag, FileReleaseFieldActive}
   308  
   309  	values := map[string]interface{}{}
   310  	var maxVersion uint64
   311  	// 查询这个 release 相关的所有
   312  	if err := loadValuesByFilter(tx, tblConfigFileRelease, fields, &ConfigFileRelease{},
   313  		func(m map[string]interface{}) bool {
   314  			flag, _ := m[FileReleaseFieldFlag].(int)
   315  			// 已经删除的不管
   316  			if flag == 1 {
   317  				return false
   318  			}
   319  			isActive, _ := m[FileReleaseFieldActive].(bool)
   320  			if !isActive {
   321  				return false
   322  			}
   323  			saveNs, _ := m[FileReleaseFieldNamespace].(string)
   324  			saveGroup, _ := m[FileReleaseFieldGroup].(string)
   325  			saveFileName, _ := m[FileReleaseFieldFileName].(string)
   326  
   327  			expect := saveNs == release.Namespace && saveGroup == release.Group &&
   328  				saveFileName == release.FileName
   329  			if expect {
   330  				saveVersion, _ := m[FileReleaseFieldVersion].(uint64)
   331  				if saveVersion > maxVersion {
   332  					maxVersion = saveVersion
   333  				}
   334  			}
   335  			return expect
   336  		}, values); err != nil {
   337  		return 0, err
   338  	}
   339  	properties := map[string]interface{}{
   340  		FileReleaseFieldActive:     false,
   341  		FileReleaseFieldModifyTime: time.Now(),
   342  	}
   343  	for key := range values {
   344  		if err := updateValue(tx, tblConfigFileRelease, key, properties); err != nil {
   345  			return 0, err
   346  		}
   347  	}
   348  	return maxVersion, nil
   349  }
   350  
   351  // CleanDeletedConfigFileRelease 清理配置发布历史
   352  func (cfr *configFileReleaseStore) CleanDeletedConfigFileRelease(endTime time.Time, limit uint64) error {
   353  
   354  	fields := []string{FileReleaseFieldModifyTime}
   355  	needDel, err := cfr.handler.LoadValuesByFilter(tblConfigFileRelease, fields,
   356  		&ConfigFileRelease{}, func(m map[string]interface{}) bool {
   357  			saveModifyTime, _ := m[FileReleaseFieldModifyTime].(time.Time)
   358  			return endTime.After(saveModifyTime)
   359  		})
   360  	if err != nil {
   361  		return err
   362  	}
   363  
   364  	keys := make([]string, 0, len(needDel))
   365  	for i := range needDel {
   366  		keys = append(keys, i)
   367  	}
   368  	return cfr.handler.DeleteValues(tblConfigFileRelease, keys)
   369  }
   370  
   371  type ConfigFileRelease struct {
   372  	Id         uint64
   373  	Name       string
   374  	Namespace  string
   375  	Group      string
   376  	FileName   string
   377  	Version    uint64
   378  	Comment    string
   379  	Md5        string
   380  	Flag       int
   381  	Active     bool
   382  	Valid      bool
   383  	Format     string
   384  	Metadata   map[string]string
   385  	CreateTime time.Time
   386  	CreateBy   string
   387  	ModifyTime time.Time
   388  	ModifyBy   string
   389  	Content    string
   390  }
   391  
   392  func (cfr *configFileReleaseStore) toModelData(data *ConfigFileRelease) *model.ConfigFileRelease {
   393  	return &model.ConfigFileRelease{
   394  		SimpleConfigFileRelease: &model.SimpleConfigFileRelease{
   395  			ConfigFileReleaseKey: &model.ConfigFileReleaseKey{
   396  				Id:        data.Id,
   397  				Name:      data.Name,
   398  				Namespace: data.Namespace,
   399  				Group:     data.Group,
   400  				FileName:  data.FileName,
   401  			},
   402  			Comment:    data.Comment,
   403  			Md5:        data.Md5,
   404  			Active:     data.Active,
   405  			Valid:      data.Valid,
   406  			Flag:       data.Flag,
   407  			Format:     data.Format,
   408  			Metadata:   data.Metadata,
   409  			Version:    data.Version,
   410  			CreateTime: data.CreateTime,
   411  			CreateBy:   data.CreateBy,
   412  			ModifyTime: data.ModifyTime,
   413  			ModifyBy:   data.ModifyBy,
   414  		},
   415  		Content: data.Content,
   416  	}
   417  }
   418  
   419  func (cfr *configFileReleaseStore) toStoreData(data *model.ConfigFileRelease) *ConfigFileRelease {
   420  	return &ConfigFileRelease{
   421  		Id:         data.Id,
   422  		Name:       data.Name,
   423  		Namespace:  data.Namespace,
   424  		Group:      data.Group,
   425  		FileName:   data.FileName,
   426  		Version:    data.Version,
   427  		Comment:    data.Comment,
   428  		Md5:        data.Md5,
   429  		Flag:       data.Flag,
   430  		Active:     data.Active,
   431  		Valid:      data.Valid,
   432  		Format:     data.Format,
   433  		Metadata:   data.Metadata,
   434  		CreateTime: data.CreateTime,
   435  		CreateBy:   data.CreateBy,
   436  		ModifyTime: data.ModifyTime,
   437  		ModifyBy:   data.ModifyBy,
   438  		Content:    data.Content,
   439  	}
   440  }