github.com/iotexproject/iotex-core@v1.14.1-rc1/db/db_bolt.go (about)

     1  // Copyright (c) 2019 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package db
     7  
     8  import (
     9  	"bytes"
    10  	"context"
    11  	"syscall"
    12  
    13  	"github.com/pkg/errors"
    14  	"github.com/prometheus/client_golang/prometheus"
    15  	bolt "go.etcd.io/bbolt"
    16  	"go.uber.org/zap"
    17  
    18  	"github.com/iotexproject/iotex-core/db/batch"
    19  	"github.com/iotexproject/iotex-core/pkg/lifecycle"
    20  	"github.com/iotexproject/iotex-core/pkg/log"
    21  	"github.com/iotexproject/iotex-core/pkg/util/byteutil"
    22  )
    23  
    24  const _fileMode = 0600
    25  
    26  var (
    27  	// ErrDBNotStarted represents the error when a db has not started
    28  	ErrDBNotStarted = errors.New("db has not started")
    29  
    30  	boltdbMtc = prometheus.NewGaugeVec(prometheus.GaugeOpts{
    31  		Name: "iotex_boltdb_metrics",
    32  		Help: "boltdb metrics.",
    33  	}, []string{"type", "method"})
    34  )
    35  
    36  func init() {
    37  	prometheus.MustRegister(boltdbMtc)
    38  }
    39  
    40  // BoltDB is KVStore implementation based bolt DB
    41  type BoltDB struct {
    42  	lifecycle.Readiness
    43  	db     *bolt.DB
    44  	path   string
    45  	config Config
    46  }
    47  
    48  // NewBoltDB instantiates an BoltDB with implements KVStore
    49  func NewBoltDB(cfg Config) *BoltDB {
    50  	return &BoltDB{
    51  		db:     nil,
    52  		path:   cfg.DbPath,
    53  		config: cfg,
    54  	}
    55  }
    56  
    57  // Start opens the BoltDB (creates new file if not existing yet)
    58  func (b *BoltDB) Start(_ context.Context) error {
    59  	opts := *bolt.DefaultOptions
    60  	if b.config.ReadOnly {
    61  		opts.ReadOnly = true
    62  	}
    63  	db, err := bolt.Open(b.path, _fileMode, &opts)
    64  	if err != nil {
    65  		return errors.Wrap(ErrIO, err.Error())
    66  	}
    67  	b.db = db
    68  	return b.TurnOn()
    69  }
    70  
    71  // Stop closes the BoltDB
    72  func (b *BoltDB) Stop(_ context.Context) error {
    73  	if err := b.TurnOff(); err != nil {
    74  		return err
    75  	}
    76  	if err := b.db.Close(); err != nil {
    77  		return errors.Wrap(ErrIO, err.Error())
    78  	}
    79  	return nil
    80  }
    81  
    82  // Put inserts a <key, value> record
    83  func (b *BoltDB) Put(namespace string, key, value []byte) (err error) {
    84  	if !b.IsReady() {
    85  		return ErrDBNotStarted
    86  	}
    87  
    88  	for c := uint8(0); c < b.config.NumRetries; c++ {
    89  		if err = b.db.Update(func(tx *bolt.Tx) error {
    90  			bucket, err := tx.CreateBucketIfNotExists([]byte(namespace))
    91  			if err != nil {
    92  				return err
    93  			}
    94  			return bucket.Put(key, value)
    95  		}); err == nil {
    96  			break
    97  		}
    98  	}
    99  	if err != nil {
   100  		if errors.Is(err, syscall.ENOSPC) {
   101  			log.L().Fatal("Failed to put db.", zap.Error(err))
   102  		}
   103  		err = errors.Wrap(ErrIO, err.Error())
   104  	}
   105  	return err
   106  }
   107  
   108  // Get retrieves a record
   109  func (b *BoltDB) Get(namespace string, key []byte) ([]byte, error) {
   110  	if !b.IsReady() {
   111  		return nil, ErrDBNotStarted
   112  	}
   113  
   114  	var value []byte
   115  	err := b.db.View(func(tx *bolt.Tx) error {
   116  		bucket := tx.Bucket([]byte(namespace))
   117  		if bucket == nil {
   118  			return errors.Wrapf(ErrNotExist, "bucket = %x doesn't exist", []byte(namespace))
   119  		}
   120  		v := bucket.Get(key)
   121  		if v == nil {
   122  			return errors.Wrapf(ErrNotExist, "key = %x doesn't exist", key)
   123  		}
   124  		value = make([]byte, len(v))
   125  		// TODO: this is not an efficient way of passing the data
   126  		copy(value, v)
   127  		return nil
   128  	})
   129  	if err == nil {
   130  		return value, nil
   131  	}
   132  	if errors.Cause(err) == ErrNotExist {
   133  		return nil, err
   134  	}
   135  	return nil, errors.Wrap(ErrIO, err.Error())
   136  }
   137  
   138  // Filter returns <k, v> pair in a bucket that meet the condition
   139  func (b *BoltDB) Filter(namespace string, cond Condition, minKey, maxKey []byte) ([][]byte, [][]byte, error) {
   140  	if !b.IsReady() {
   141  		return nil, nil, ErrDBNotStarted
   142  	}
   143  
   144  	var fk, fv [][]byte
   145  	if err := b.db.View(func(tx *bolt.Tx) error {
   146  		bucket := tx.Bucket([]byte(namespace))
   147  		if bucket == nil {
   148  			return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", []byte(namespace))
   149  		}
   150  
   151  		var k, v []byte
   152  		c := bucket.Cursor()
   153  		if len(minKey) > 0 {
   154  			k, v = c.Seek(minKey)
   155  		} else {
   156  			k, v = c.First()
   157  		}
   158  
   159  		if k == nil {
   160  			return nil
   161  		}
   162  
   163  		checkMax := len(maxKey) > 0
   164  		for ; k != nil; k, v = c.Next() {
   165  			if checkMax && bytes.Compare(k, maxKey) == 1 {
   166  				return nil
   167  			}
   168  			if cond(k, v) {
   169  				key := make([]byte, len(k))
   170  				copy(key, k)
   171  				value := make([]byte, len(v))
   172  				copy(value, v)
   173  				fk = append(fk, key)
   174  				fv = append(fv, value)
   175  			}
   176  		}
   177  		return nil
   178  	}); err != nil {
   179  		return nil, nil, err
   180  	}
   181  
   182  	if len(fk) == 0 {
   183  		return nil, nil, errors.Wrap(ErrNotExist, "filter returns no match")
   184  	}
   185  	return fk, fv, nil
   186  }
   187  
   188  // Range retrieves values for a range of keys
   189  func (b *BoltDB) Range(namespace string, key []byte, count uint64) ([][]byte, error) {
   190  	if !b.IsReady() {
   191  		return nil, ErrDBNotStarted
   192  	}
   193  
   194  	value := make([][]byte, count)
   195  	err := b.db.View(func(tx *bolt.Tx) error {
   196  		bucket := tx.Bucket([]byte(namespace))
   197  		if bucket == nil {
   198  			return errors.Wrapf(ErrNotExist, "bucket = %s doesn't exist", namespace)
   199  		}
   200  		// seek to start
   201  		cur := bucket.Cursor()
   202  		k, v := cur.Seek(key)
   203  		if k == nil {
   204  			return errors.Wrapf(ErrNotExist, "entry for key 0x%x doesn't exist", key)
   205  		}
   206  		// retrieve 'count' items
   207  		for i := uint64(0); i < count; i++ {
   208  			if k == nil {
   209  				return errors.Wrapf(ErrNotExist, "entry for key 0x%x doesn't exist", k)
   210  			}
   211  			value[i] = make([]byte, len(v))
   212  			copy(value[i], v)
   213  			k, v = cur.Next()
   214  		}
   215  		return nil
   216  	})
   217  	if err == nil {
   218  		return value, nil
   219  	}
   220  	if errors.Cause(err) == ErrNotExist {
   221  		return nil, err
   222  	}
   223  	return nil, errors.Wrap(ErrIO, err.Error())
   224  }
   225  
   226  // GetBucketByPrefix retrieves all bucket those with const namespace prefix
   227  func (b *BoltDB) GetBucketByPrefix(namespace []byte) ([][]byte, error) {
   228  	if !b.IsReady() {
   229  		return nil, ErrDBNotStarted
   230  	}
   231  
   232  	allKey := make([][]byte, 0)
   233  	err := b.db.View(func(tx *bolt.Tx) error {
   234  		if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error {
   235  			if bytes.HasPrefix(name, namespace) && !bytes.Equal(name, namespace) {
   236  				temp := make([]byte, len(name))
   237  				copy(temp, name)
   238  				allKey = append(allKey, temp)
   239  			}
   240  			return nil
   241  		}); err != nil {
   242  			return err
   243  		}
   244  		return nil
   245  	})
   246  	return allKey, err
   247  }
   248  
   249  // GetKeyByPrefix retrieves all keys those with const prefix
   250  func (b *BoltDB) GetKeyByPrefix(namespace, prefix []byte) ([][]byte, error) {
   251  	if !b.IsReady() {
   252  		return nil, ErrDBNotStarted
   253  	}
   254  
   255  	allKey := make([][]byte, 0)
   256  	err := b.db.View(func(tx *bolt.Tx) error {
   257  		buck := tx.Bucket(namespace)
   258  		if buck == nil {
   259  			return ErrNotExist
   260  		}
   261  		c := buck.Cursor()
   262  		for k, _ := c.Seek(prefix); bytes.HasPrefix(k, prefix); k, _ = c.Next() {
   263  			temp := make([]byte, len(k))
   264  			copy(temp, k)
   265  			allKey = append(allKey, temp)
   266  		}
   267  		return nil
   268  	})
   269  	return allKey, err
   270  }
   271  
   272  // Delete deletes a record,if key is nil,this will delete the whole bucket
   273  func (b *BoltDB) Delete(namespace string, key []byte) (err error) {
   274  	if !b.IsReady() {
   275  		return ErrDBNotStarted
   276  	}
   277  
   278  	numRetries := b.config.NumRetries
   279  	for c := uint8(0); c < numRetries; c++ {
   280  		if key == nil {
   281  			err = b.db.Update(func(tx *bolt.Tx) error {
   282  				if err := tx.DeleteBucket([]byte(namespace)); err != bolt.ErrBucketNotFound {
   283  					return err
   284  				}
   285  				return nil
   286  			})
   287  		} else {
   288  			err = b.db.Update(func(tx *bolt.Tx) error {
   289  				bucket := tx.Bucket([]byte(namespace))
   290  				if bucket == nil {
   291  					return nil
   292  				}
   293  				return bucket.Delete(key)
   294  			})
   295  		}
   296  		if err == nil {
   297  			break
   298  		}
   299  	}
   300  	if err != nil {
   301  		if errors.Is(err, syscall.ENOSPC) {
   302  			log.L().Fatal("Failed to delete db.", zap.Error(err))
   303  		}
   304  		err = errors.Wrap(ErrIO, err.Error())
   305  	}
   306  	return err
   307  }
   308  
   309  // WriteBatch commits a batch
   310  func (b *BoltDB) WriteBatch(kvsb batch.KVStoreBatch) (err error) {
   311  	if !b.IsReady() {
   312  		return ErrDBNotStarted
   313  	}
   314  
   315  	kvsb.Lock()
   316  	defer kvsb.Unlock()
   317  
   318  	type doubleKey struct {
   319  		ns  string
   320  		key string
   321  	}
   322  	// remove duplicate keys, only keep the last write for each key
   323  	entryKeySet := make(map[doubleKey]struct{})
   324  	uniqEntries := make([]*batch.WriteInfo, 0)
   325  	for i := kvsb.Size() - 1; i >= 0; i-- {
   326  		write, e := kvsb.Entry(i)
   327  		if e != nil {
   328  			return e
   329  		}
   330  		// only handle Put and Delete
   331  		if write.WriteType() != batch.Put && write.WriteType() != batch.Delete {
   332  			continue
   333  		}
   334  		k := doubleKey{ns: write.Namespace(), key: string(write.Key())}
   335  		if _, ok := entryKeySet[k]; !ok {
   336  			entryKeySet[k] = struct{}{}
   337  			uniqEntries = append(uniqEntries, write)
   338  		}
   339  	}
   340  	boltdbMtc.WithLabelValues(b.path, "entrySize").Set(float64(kvsb.Size()))
   341  	boltdbMtc.WithLabelValues(b.path, "uniqueEntrySize").Set(float64(len(entryKeySet)))
   342  	for c := uint8(0); c < b.config.NumRetries; c++ {
   343  		if err = b.db.Update(func(tx *bolt.Tx) error {
   344  			// keep order of the writes same as the original batch
   345  			for i := len(uniqEntries) - 1; i >= 0; i-- {
   346  				write := uniqEntries[i]
   347  				ns := write.Namespace()
   348  				switch write.WriteType() {
   349  				case batch.Put:
   350  					bucket, e := tx.CreateBucketIfNotExists([]byte(ns))
   351  					if e != nil {
   352  						return errors.Wrap(e, write.Error())
   353  					}
   354  					if p, ok := kvsb.CheckFillPercent(ns); ok {
   355  						bucket.FillPercent = p
   356  					}
   357  					if e := bucket.Put(write.Key(), write.Value()); e != nil {
   358  						return errors.Wrap(e, write.Error())
   359  					}
   360  				case batch.Delete:
   361  					bucket := tx.Bucket([]byte(ns))
   362  					if bucket == nil {
   363  						continue
   364  					}
   365  					if e := bucket.Delete(write.Key()); e != nil {
   366  						return errors.Wrap(e, write.Error())
   367  					}
   368  				}
   369  			}
   370  			return nil
   371  		}); err == nil {
   372  			break
   373  		}
   374  	}
   375  
   376  	if err != nil {
   377  		if errors.Is(err, syscall.ENOSPC) {
   378  			log.L().Fatal("Failed to write batch db.", zap.Error(err))
   379  		}
   380  		err = errors.Wrap(ErrIO, err.Error())
   381  	}
   382  	return err
   383  }
   384  
   385  // BucketExists returns true if bucket exists
   386  func (b *BoltDB) BucketExists(namespace string) bool {
   387  	if !b.IsReady() {
   388  		log.L().Debug(ErrDBNotStarted.Error())
   389  		return false
   390  	}
   391  
   392  	var exist bool
   393  	_ = b.db.View(func(tx *bolt.Tx) error {
   394  		bucket := tx.Bucket([]byte(namespace))
   395  		if bucket != nil {
   396  			exist = true
   397  		}
   398  		return nil
   399  	})
   400  	return exist
   401  }
   402  
   403  // ======================================
   404  // below functions used by RangeIndex
   405  // ======================================
   406  
   407  // Insert inserts a value into the index
   408  func (b *BoltDB) Insert(name []byte, key uint64, value []byte) error {
   409  	if !b.IsReady() {
   410  		return ErrDBNotStarted
   411  	}
   412  
   413  	var err error
   414  	for i := uint8(0); i < b.config.NumRetries; i++ {
   415  		if err = b.db.Update(func(tx *bolt.Tx) error {
   416  			bucket := tx.Bucket(name)
   417  			if bucket == nil {
   418  				return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", name)
   419  			}
   420  			cur := bucket.Cursor()
   421  			ak := byteutil.Uint64ToBytesBigEndian(key - 1)
   422  			k, v := cur.Seek(ak)
   423  			if !bytes.Equal(k, ak) {
   424  				// insert new key
   425  				if err := bucket.Put(ak, v); err != nil {
   426  					return err
   427  				}
   428  			} else {
   429  				// update an existing key
   430  				k, _ = cur.Next()
   431  			}
   432  			if k != nil {
   433  				return bucket.Put(k, value)
   434  			}
   435  			return nil
   436  		}); err == nil {
   437  			break
   438  		}
   439  	}
   440  	if err != nil {
   441  		if errors.Is(err, syscall.ENOSPC) {
   442  			log.L().Fatal("Failed to insert db.", zap.Error(err))
   443  		}
   444  		return errors.Wrap(ErrIO, err.Error())
   445  	}
   446  	return nil
   447  }
   448  
   449  // SeekNext returns value by the key (if key not exist, use next key)
   450  func (b *BoltDB) SeekNext(name []byte, key uint64) ([]byte, error) {
   451  	if !b.IsReady() {
   452  		return nil, ErrDBNotStarted
   453  	}
   454  
   455  	var value []byte
   456  	err := b.db.View(func(tx *bolt.Tx) error {
   457  		bucket := tx.Bucket(name)
   458  		if bucket == nil {
   459  			return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", name)
   460  		}
   461  		// seek to start
   462  		cur := bucket.Cursor()
   463  		_, v := cur.Seek(byteutil.Uint64ToBytesBigEndian(key))
   464  		value = make([]byte, len(v))
   465  		copy(value, v)
   466  		return nil
   467  	})
   468  	if err != nil {
   469  		return nil, err
   470  	}
   471  	return value, nil
   472  }
   473  
   474  // SeekPrev returns value by the key (if key not exist, use previous key)
   475  func (b *BoltDB) SeekPrev(name []byte, key uint64) ([]byte, error) {
   476  	if !b.IsReady() {
   477  		return nil, ErrDBNotStarted
   478  	}
   479  
   480  	var value []byte
   481  	if err := b.db.View(func(tx *bolt.Tx) error {
   482  		bucket := tx.Bucket(name)
   483  		if bucket == nil {
   484  			return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", name)
   485  		}
   486  		// seek to start
   487  		cur := bucket.Cursor()
   488  		cur.Seek(byteutil.Uint64ToBytesBigEndian(key))
   489  		_, v := cur.Prev()
   490  		value = make([]byte, len(v))
   491  		copy(value, v)
   492  		return nil
   493  	}); err != nil {
   494  		return nil, err
   495  	}
   496  	return value, nil
   497  }
   498  
   499  // Remove removes an existing key
   500  func (b *BoltDB) Remove(name []byte, key uint64) error {
   501  	if !b.IsReady() {
   502  		return ErrDBNotStarted
   503  	}
   504  
   505  	var err error
   506  	for i := uint8(0); i < b.config.NumRetries; i++ {
   507  		if err = b.db.Update(func(tx *bolt.Tx) error {
   508  			bucket := tx.Bucket(name)
   509  			if bucket == nil {
   510  				return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", name)
   511  			}
   512  			cur := bucket.Cursor()
   513  			ak := byteutil.Uint64ToBytesBigEndian(key - 1)
   514  			k, v := cur.Seek(ak)
   515  			if !bytes.Equal(k, ak) {
   516  				// return nil if the key does not exist
   517  				return nil
   518  			}
   519  			if err := bucket.Delete(ak); err != nil {
   520  				return err
   521  			}
   522  			// write the corresponding value to next key
   523  			k, _ = cur.Next()
   524  			if k != nil {
   525  				return bucket.Put(k, v)
   526  			}
   527  			return nil
   528  		}); err == nil {
   529  			break
   530  		}
   531  	}
   532  
   533  	if err != nil {
   534  		if errors.Is(err, syscall.ENOSPC) {
   535  			log.L().Fatal("Failed to remove db.", zap.Error(err))
   536  		}
   537  		err = errors.Wrap(ErrIO, err.Error())
   538  	}
   539  	return err
   540  }
   541  
   542  // Purge deletes an existing key and all keys before it
   543  func (b *BoltDB) Purge(name []byte, key uint64) error {
   544  	if !b.IsReady() {
   545  		return ErrDBNotStarted
   546  	}
   547  
   548  	var err error
   549  	for i := uint8(0); i < b.config.NumRetries; i++ {
   550  		if err = b.db.Update(func(tx *bolt.Tx) error {
   551  			bucket := tx.Bucket(name)
   552  			if bucket == nil {
   553  				return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", name)
   554  			}
   555  			cur := bucket.Cursor()
   556  			nk, _ := cur.Seek(byteutil.Uint64ToBytesBigEndian(key))
   557  			// delete all keys before this key
   558  			for k, _ := cur.Prev(); k != nil; k, _ = cur.Prev() {
   559  				if err := bucket.Delete(k); err != nil {
   560  					return err
   561  				}
   562  			}
   563  			// write not exist value to next key
   564  			if nk != nil {
   565  				return bucket.Put(nk, NotExist)
   566  			}
   567  			return nil
   568  		}); err == nil {
   569  			break
   570  		}
   571  	}
   572  
   573  	if err != nil {
   574  		if errors.Is(err, syscall.ENOSPC) {
   575  			log.L().Fatal("Failed to purge db.", zap.Error(err))
   576  		}
   577  		err = errors.Wrap(ErrIO, err.Error())
   578  	}
   579  	return err
   580  }
   581  
   582  // ======================================
   583  // private functions
   584  // ======================================
   585  
   586  // intentionally fail to test DB can successfully rollback
   587  func (b *BoltDB) batchPutForceFail(namespace string, key [][]byte, value [][]byte) error {
   588  	if !b.IsReady() {
   589  		return ErrDBNotStarted
   590  	}
   591  
   592  	return b.db.Update(func(tx *bolt.Tx) error {
   593  		bucket, err := tx.CreateBucketIfNotExists([]byte(namespace))
   594  		if err != nil {
   595  			return err
   596  		}
   597  		if len(key) != len(value) {
   598  			return errors.Wrap(ErrIO, "batch put <k, v> size not match")
   599  		}
   600  		for i := 0; i < len(key); i++ {
   601  			if err := bucket.Put(key[i], value[i]); err != nil {
   602  				return err
   603  			}
   604  			// intentionally fail to test DB can successfully rollback
   605  			if i == len(key)-1 {
   606  				return errors.Wrapf(ErrIO, "force fail to test DB rollback")
   607  			}
   608  		}
   609  		return nil
   610  	})
   611  }