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 }