github.com/polarismesh/polaris@v1.17.8/store/boltdb/handler.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 "reflect" 24 "time" 25 26 "github.com/golang/protobuf/proto" 27 bolt "go.etcd.io/bbolt" 28 29 "github.com/polarismesh/polaris/store" 30 ) 31 32 const ( 33 DeleteFlagValue byte = 1 34 DataValidFieldName string = "Valid" 35 ) 36 37 var ( 38 ErrorValueInvisible = errors.New("value is Invisible") 39 ) 40 41 type IDHolder struct { 42 ID uint64 43 } 44 45 // BoltHandler encapsulate operations around boltdb 46 type BoltHandler interface { 47 48 // SaveValue insert data object, each data object should be identified by unique key 49 SaveValue(typ string, key string, object interface{}) error 50 51 // DeleteValues delete data object by unique key 52 DeleteValues(typ string, key []string) error 53 54 // UpdateValue update properties of data object 55 UpdateValue(typ string, key string, properties map[string]interface{}) error 56 57 // LoadValues load data objects by unique keys, return value is 'key->object' map 58 LoadValues(typ string, keys []string, typObject interface{}) (map[string]interface{}, error) 59 60 // LoadValuesByFilter filter data objects by condition, return value is 'key->object' map 61 LoadValuesByFilter(typ string, fields []string, 62 typObject interface{}, filter func(map[string]interface{}) bool) (map[string]interface{}, error) 63 64 // LoadValuesAll load all saved data objects, return value is 'key->object' map 65 LoadValuesAll(typ string, typObject interface{}) (map[string]interface{}, error) 66 67 // IterateFields iterate all saved data objects 68 IterateFields(typ string, field string, typObject interface{}, process func(interface{})) error 69 70 // CountValues count all data objects 71 CountValues(typ string) (int, error) 72 73 // Execute execute scripts directly 74 Execute(writable bool, process func(tx *bolt.Tx) error) error 75 76 // StartTx start new tx 77 StartTx() (store.Tx, error) 78 79 // Close boltdb 80 Close() error 81 } 82 83 // BoltConfig config to initialize boltdb 84 type BoltConfig struct { 85 // FileName boltdb store file 86 FileName string 87 } 88 89 const ( 90 confPath = "path" 91 defaultPath = "./polaris.bolt" 92 ) 93 94 // Parse parse yaml config 95 func (c *BoltConfig) Parse(opt map[string]interface{}) { 96 if value, ok := opt[confPath]; ok { 97 c.FileName = value.(string) 98 } else { 99 c.FileName = defaultPath 100 } 101 } 102 103 const ( 104 defaultTimeoutForFileLock = 5 * time.Second 105 ) 106 107 // NewBoltHandler create the boltdb handler 108 func NewBoltHandler(config *BoltConfig) (BoltHandler, error) { 109 db, err := openBoltDB(config.FileName) 110 if err != nil { 111 return nil, err 112 } 113 return &boltHandler{db: db}, nil 114 } 115 116 type boltHandler struct { 117 db *bolt.DB 118 } 119 120 func openBoltDB(path string) (*bolt.DB, error) { 121 return bolt.Open(path, 0600, &bolt.Options{ 122 Timeout: defaultTimeoutForFileLock, 123 }) 124 } 125 126 // SaveValue insert data object, each data object should be identified by unique key 127 func (b *boltHandler) SaveValue(typ string, key string, value interface{}) error { 128 return b.db.Update(func(tx *bolt.Tx) error { 129 return saveValue(tx, typ, key, value) 130 }) 131 } 132 133 // saveValue Save data to boltdb, need to display incoming transactions 134 // 135 // @param tx bolt.Tx 136 // @param typ table name 137 // @param key uniq key 138 // @param value record value 139 // @return error if save failed, return error 140 func saveValue(tx *bolt.Tx, typ string, key string, value interface{}) error { 141 var typBucket *bolt.Bucket 142 var err error 143 typBucket, err = tx.CreateBucketIfNotExists([]byte(typ)) 144 if err != nil { 145 return err 146 } 147 keyBuf := []byte(key) 148 var bucket *bolt.Bucket 149 // 先清理老数据 150 bucket = typBucket.Bucket(keyBuf) 151 if bucket != nil { 152 if err = typBucket.DeleteBucket(keyBuf); err != nil { 153 return err 154 } 155 } 156 // 创建全新bucket 157 bucket, err = typBucket.CreateBucket(keyBuf) 158 if err != nil { 159 return err 160 } 161 var buffers map[string][]byte 162 buffers, err = serializeObject(bucket, value) 163 if err != nil { 164 return err 165 } 166 if len(buffers) > 0 { 167 for k, v := range buffers { 168 err = bucket.Put([]byte(k), v) 169 if err != nil { 170 return err 171 } 172 } 173 _ = bucket.Put([]byte(toBucketField(DataValidFieldName)), encodeBoolBuffer(true)) 174 } 175 return err 176 } 177 178 // LoadValues load data objects by unique keys, return value is 'key->object' map 179 func (b *boltHandler) LoadValues(typ string, keys []string, typObject interface{}) (map[string]interface{}, error) { 180 var values = make(map[string]interface{}) 181 if len(keys) == 0 { 182 return values, nil 183 } 184 err := b.db.View(func(tx *bolt.Tx) error { 185 return loadValues(tx, typ, keys, typObject, values) 186 }) 187 return values, err 188 } 189 190 func loadValues(tx *bolt.Tx, typ string, keys []string, typObject interface{}, values map[string]interface{}) error { 191 for _, key := range keys { 192 bucket := getBucket(tx, typ, key) 193 if bucket == nil { 194 continue 195 } 196 toObj, err := deserializeObject(bucket, typObject) 197 if err != nil { 198 return err 199 } 200 values[key] = toObj 201 } 202 return nil 203 } 204 205 // LoadValuesByFilter filter data objects by condition, return value is 'key->object' map 206 func (b *boltHandler) LoadValuesByFilter(typ string, fields []string, 207 typObject interface{}, filter func(map[string]interface{}) bool) (map[string]interface{}, error) { 208 values := make(map[string]interface{}) 209 err := b.db.View(func(tx *bolt.Tx) error { 210 return loadValuesByFilter(tx, typ, fields, typObject, filter, values) 211 }) 212 return values, err 213 } 214 215 func loadValuesByFilter(tx *bolt.Tx, typ string, fields []string, typObject interface{}, 216 filter func(map[string]interface{}) bool, values map[string]interface{}) error { 217 typeBucket := tx.Bucket([]byte(typ)) 218 if typeBucket == nil { 219 return nil 220 } 221 keys, err := getKeys(typeBucket) 222 if err != nil { 223 return err 224 } 225 if len(keys) == 0 { 226 return nil 227 } 228 for _, key := range keys { 229 bucket := typeBucket.Bucket([]byte(key)) 230 if bucket == nil { 231 log.Warnf("[BlobStore] bucket not found for key %s, type %s", key, typ) 232 continue 233 } 234 235 var matchResult bool 236 matchResult, err = matchObject(bucket, fields, typObject, filter) 237 if err != nil { 238 return err 239 } 240 if !matchResult { 241 continue 242 } 243 var targetObj interface{} 244 targetObj, err = deserializeObject(bucket, typObject) 245 if err != nil { 246 return err 247 } 248 values[key] = targetObj 249 } 250 return nil 251 } 252 253 func reflectProtoMsg(typObject interface{}, fieldName string) (proto.Message, error) { 254 intoType := indirectType(reflect.TypeOf(typObject)) 255 field, ok := intoType.FieldByName(fieldName) 256 if !ok { 257 return nil, fmt.Errorf("field %s not found in object %v", fieldName, intoType) 258 } 259 rawFieldType := field.Type 260 if !rawFieldType.Implements(messageType) { 261 return nil, fmt.Errorf("field %s type not match in object %v, want %v, get %v", 262 fieldName, intoType, messageType, field.Type) 263 } 264 return reflect.New(rawFieldType.Elem()).Interface().(proto.Message), nil 265 } 266 267 func reflectMapMsg(bucket *bolt.Bucket, bucketField string) (map[string]string, error) { 268 subBucket := bucket.Bucket([]byte(bucketField)) 269 if subBucket == nil { 270 return nil, nil 271 } 272 values := make(map[string]string) 273 err := subBucket.ForEach(func(k, v []byte) error { 274 values[string(k)] = string(v) 275 return nil 276 }) 277 if err != nil { 278 return nil, err 279 } 280 return values, nil 281 } 282 283 func getFieldObject(bucket *bolt.Bucket, typObject interface{}, field string) (interface{}, error) { 284 bucketField := toBucketField(field) 285 valueBytes := bucket.Get([]byte(bucketField)) 286 if len(valueBytes) == 0 { 287 return reflectMapMsg(bucket, bucketField) 288 } 289 typByte := valueBytes[0] 290 switch typByte { 291 case typeString: 292 value, _ := decodeStringBuffer(bucketField, valueBytes) 293 return value, nil 294 case typeBool: 295 value, _ := decodeBoolBuffer(bucketField, valueBytes) 296 return value, nil 297 case typeTime: 298 value, _ := decodeTimeBuffer(bucketField, valueBytes) 299 return value, nil 300 case typeProtobuf: 301 msg, err := reflectProtoMsg(typObject, field) 302 if err != nil { 303 return false, err 304 } 305 value, err := decodeMessageBuffer(msg, field, valueBytes) 306 if err != nil { 307 return false, err 308 } 309 return value, nil 310 case typeInt, typeInt8, typeInt16, typeInt32, typeInt64: 311 value, _ := decodeIntBuffer(field, valueBytes, typByte) 312 return value, nil 313 case typeUint, typeUint8, typeUint16, typeUint32, typeUint64: 314 value, _ := decodeUintBuffer(field, valueBytes, typByte) 315 return value, nil 316 default: 317 log.Warnf( 318 "[BlobStore] matchObject unrecognized field %s, type is %d", field, typByte) 319 return nil, nil 320 } 321 } 322 323 func matchObject(bucket *bolt.Bucket, 324 fields []string, typObject interface{}, filter func(map[string]interface{}) bool) (bool, error) { 325 if len(fields) == 0 { 326 return true, nil 327 } 328 if filter == nil { 329 return true, nil 330 } 331 fieldValues := make(map[string]interface{}) 332 for _, field := range fields { 333 value, err := getFieldObject(bucket, typObject, field) 334 if err != nil { 335 if errors.Is(err, ErrorValueInvisible) { 336 continue 337 } 338 return false, err 339 } 340 if value == nil { 341 continue 342 } 343 fieldValues[field] = value 344 } 345 return filter(fieldValues), nil 346 } 347 348 // IterateFields iterate all saved data objects 349 func (b *boltHandler) IterateFields(typ string, field string, typObject interface{}, filter func(interface{})) error { 350 if filter == nil { 351 return nil 352 } 353 return b.db.View(func(tx *bolt.Tx) error { 354 typeBucket := tx.Bucket([]byte(typ)) 355 if typeBucket == nil { 356 return nil 357 } 358 keys, err := getKeys(typeBucket) 359 if err != nil { 360 return err 361 } 362 if len(keys) == 0 { 363 return nil 364 } 365 for _, key := range keys { 366 bucket := typeBucket.Bucket([]byte(key)) 367 if bucket == nil { 368 log.Warnf("[BlobStore] bucket not found for key %s, type %s", key, typ) 369 continue 370 } 371 var fieldObj interface{} 372 fieldObj, err = getFieldObject(bucket, typObject, field) 373 if err != nil { 374 return err 375 } 376 filter(fieldObj) 377 } 378 return nil 379 }) 380 } 381 382 // Close boltdb 383 func (b *boltHandler) Close() error { 384 if b.db != nil { 385 return b.db.Close() 386 } 387 return nil 388 } 389 390 // DeleteValues delete data object by unique key 391 func (b *boltHandler) DeleteValues(typ string, keys []string) error { 392 if len(keys) == 0 { 393 return nil 394 } 395 return b.db.Update(func(tx *bolt.Tx) error { 396 return deleteValues(tx, typ, keys) 397 }) 398 } 399 400 func deleteValues(tx *bolt.Tx, typ string, keys []string) error { 401 typeBucket := tx.Bucket([]byte(typ)) 402 if typeBucket == nil { 403 return nil 404 } 405 for _, key := range keys { 406 keyBytes := []byte(key) 407 if subBucket := typeBucket.Bucket(keyBytes); subBucket != nil { 408 if err := typeBucket.DeleteBucket(keyBytes); err != nil { 409 return err 410 } 411 } 412 } 413 return nil 414 } 415 416 func getBucket(tx *bolt.Tx, typ string, key string) *bolt.Bucket { 417 bucket := tx.Bucket([]byte(typ)) 418 if bucket == nil { 419 return nil 420 } 421 return bucket.Bucket([]byte(key)) 422 } 423 424 func convertInt64Value(value interface{}, kind reflect.Kind) int64 { 425 switch kind { 426 case reflect.Int: 427 return int64(value.(int)) 428 case reflect.Int8: 429 return int64(value.(int8)) 430 case reflect.Int16: 431 return int64(value.(int16)) 432 case reflect.Int32: 433 return int64(value.(int32)) 434 case reflect.Int64: 435 return value.(int64) 436 } 437 return 0 438 } 439 440 func convertUint64Value(value interface{}, kind reflect.Kind) uint64 { 441 switch kind { 442 case reflect.Uint: 443 return uint64(value.(uint)) 444 case reflect.Uint8: 445 return uint64(value.(uint8)) 446 case reflect.Uint16: 447 return uint64(value.(uint16)) 448 case reflect.Uint32: 449 return uint64(value.(uint32)) 450 case reflect.Uint64: 451 return value.(uint64) 452 } 453 return 0 454 } 455 456 func getKeys(bucket *bolt.Bucket) ([]string, error) { 457 keys := make([]string, 0) 458 err := bucket.ForEach(func(k, v []byte) error { 459 keys = append(keys, string(k)) 460 return nil 461 }) 462 return keys, err 463 } 464 465 // CountValues count all data objects 466 func (b *boltHandler) CountValues(typ string) (int, error) { 467 var count int 468 err := b.db.View(func(tx *bolt.Tx) error { 469 ret, err := countValues(tx, typ) 470 count = ret 471 return err 472 }) 473 return count, err 474 } 475 476 func countValues(tx *bolt.Tx, typ string) (int, error) { 477 var count int 478 typeBucket := tx.Bucket([]byte(typ)) 479 if typeBucket == nil { 480 return 0, nil 481 } 482 err := typeBucket.ForEach(func(k, v []byte) error { 483 subBucket := typeBucket.Bucket(k) 484 canCount := true 485 486 if subBucket != nil { 487 data := subBucket.Get([]byte(toBucketField(DataValidFieldName))) 488 if len(data) == 0 { 489 canCount = true 490 } else { 491 val, err := decodeBoolBuffer(DataValidFieldName, data) 492 if err != nil { 493 return err 494 } 495 canCount = val 496 } 497 } 498 if canCount { 499 count++ 500 } 501 return nil 502 }) 503 return count, err 504 } 505 506 // UpdateValue update properties of data object 507 func (b *boltHandler) UpdateValue(typ string, key string, properties map[string]interface{}) error { 508 return b.db.Update(func(tx *bolt.Tx) error { 509 return updateValue(tx, typ, key, properties) 510 }) 511 } 512 513 func updateValue(tx *bolt.Tx, typ string, key string, properties map[string]interface{}) error { 514 var err error 515 typeBucket := tx.Bucket([]byte(typ)) 516 if typeBucket == nil { 517 return nil 518 } 519 bucket := typeBucket.Bucket([]byte(key)) 520 if bucket == nil { 521 return nil 522 } 523 if len(properties) == 0 { 524 return nil 525 } 526 for propKey, propValue := range properties { 527 bucketKey := toBucketField(propKey) 528 propType := reflect.TypeOf(propValue) 529 kind := propType.Kind() 530 switch kind { 531 case reflect.String: 532 err = bucket.Put([]byte(bucketKey), encodeStringBuffer(propValue.(string))) 533 case reflect.Bool: 534 err = bucket.Put([]byte(bucketKey), encodeBoolBuffer(propValue.(bool))) 535 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 536 err = bucket.Put([]byte(bucketKey), 537 encodeIntBuffer(convertInt64Value(propValue, kind), numberKindToType[kind])) 538 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 539 err = bucket.Put([]byte(bucketKey), 540 encodeUintBuffer(convertUint64Value(propValue, kind), numberKindToType[kind])) 541 case reflect.Map: 542 err = encodeRawMap(bucket, bucketKey, propValue.(map[string]string)) 543 case reflect.Ptr: 544 if propType.Implements(messageType) { 545 // protobuf类型 546 var msgBuf []byte 547 msgBuf, err = encodeMessageBuffer(propValue.(proto.Message)) 548 if err != nil { 549 return err 550 } 551 err = bucket.Put([]byte(bucketKey), msgBuf) 552 } 553 case reflect.Struct: 554 if propType.AssignableTo(timeType) { 555 // 时间类型 556 err = bucket.Put([]byte(bucketKey), encodeTimeBuffer(propValue.(time.Time))) 557 } 558 } 559 if err != nil { 560 return err 561 } 562 } 563 return nil 564 } 565 566 // LoadValuesAll load all saved data objects, return value is 'key->object' map 567 func (b *boltHandler) LoadValuesAll(typ string, typObject interface{}) (map[string]interface{}, error) { 568 values := make(map[string]interface{}) 569 err := b.db.View(func(tx *bolt.Tx) error { 570 typeBucket := tx.Bucket([]byte(typ)) 571 if typeBucket == nil { 572 return nil 573 } 574 keys, err := getKeys(typeBucket) 575 if err != nil { 576 return err 577 } 578 if len(keys) == 0 { 579 return nil 580 } 581 for _, key := range keys { 582 bucket := typeBucket.Bucket([]byte(key)) 583 if bucket == nil { 584 log.Warnf("[BlobStore] bucket not found for key %s, type %s", key, typ) 585 continue 586 } 587 var targetObj interface{} 588 targetObj, err = deserializeObject(bucket, typObject) 589 if err != nil { 590 return err 591 } 592 values[key] = targetObj 593 } 594 return nil 595 }) 596 return values, err 597 } 598 599 // Execute execute scripts directly 600 func (b *boltHandler) Execute(writable bool, process func(tx *bolt.Tx) error) error { 601 if writable { 602 return b.db.Update(process) 603 } 604 return b.db.View(process) 605 } 606 607 // StartTx start a new tx 608 func (b *boltHandler) StartTx() (store.Tx, error) { 609 tx, err := b.db.Begin(true) 610 if err != nil { 611 return nil, err 612 } 613 return NewBoltTx(tx), nil 614 }