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  }