github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/ledger/blkstorage/blockstore_provider.go (about)

     1  /*
     2  Copyright hechain. 2017 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package blkstorage
     8  
     9  import (
    10  	"os"
    11  
    12  	"github.com/hechain20/hechain/common/flogging"
    13  	"github.com/hechain20/hechain/common/ledger/dataformat"
    14  	"github.com/hechain20/hechain/common/ledger/util/leveldbhelper"
    15  	"github.com/hechain20/hechain/common/metrics"
    16  	"github.com/hechain20/hechain/internal/fileutil"
    17  	"github.com/pkg/errors"
    18  )
    19  
    20  var logger = flogging.MustGetLogger("blkstorage")
    21  
    22  // IndexableAttr represents an indexable attribute
    23  type IndexableAttr string
    24  
    25  // constants for indexable attributes
    26  const (
    27  	IndexableAttrBlockNum        = IndexableAttr("BlockNum")
    28  	IndexableAttrBlockHash       = IndexableAttr("BlockHash")
    29  	IndexableAttrTxID            = IndexableAttr("TxID")
    30  	IndexableAttrBlockNumTranNum = IndexableAttr("BlockNumTranNum")
    31  )
    32  
    33  // IndexConfig - a configuration that includes a list of attributes that should be indexed
    34  type IndexConfig struct {
    35  	AttrsToIndex []IndexableAttr
    36  }
    37  
    38  // SnapshotInfo captures some of the details about the snapshot
    39  type SnapshotInfo struct {
    40  	LastBlockNum      uint64
    41  	LastBlockHash     []byte
    42  	PreviousBlockHash []byte
    43  }
    44  
    45  // Contains returns true iff the supplied parameter is present in the IndexConfig.AttrsToIndex
    46  func (c *IndexConfig) Contains(indexableAttr IndexableAttr) bool {
    47  	for _, a := range c.AttrsToIndex {
    48  		if a == indexableAttr {
    49  			return true
    50  		}
    51  	}
    52  	return false
    53  }
    54  
    55  // BlockStoreProvider provides handle to block storage - this is not thread-safe
    56  type BlockStoreProvider struct {
    57  	conf            *Conf
    58  	indexConfig     *IndexConfig
    59  	leveldbProvider *leveldbhelper.Provider
    60  	stats           *stats
    61  }
    62  
    63  // NewProvider constructs a filesystem based block store provider
    64  func NewProvider(conf *Conf, indexConfig *IndexConfig, metricsProvider metrics.Provider) (*BlockStoreProvider, error) {
    65  	dbConf := &leveldbhelper.Conf{
    66  		DBPath:         conf.getIndexDir(),
    67  		ExpectedFormat: dataFormatVersion(indexConfig),
    68  	}
    69  
    70  	p, err := leveldbhelper.NewProvider(dbConf)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	dirPath := conf.getChainsDir()
    76  	if _, err := os.Stat(dirPath); err != nil {
    77  		if !os.IsNotExist(err) { // NotExist is the only permitted error type
    78  			return nil, errors.Wrapf(err, "failed to read ledger directory %s", dirPath)
    79  		}
    80  
    81  		logger.Info("Creating new file ledger directory at", dirPath)
    82  		if err = os.MkdirAll(dirPath, 0o755); err != nil {
    83  			return nil, errors.Wrapf(err, "failed to create ledger directory: %s", dirPath)
    84  		}
    85  	}
    86  
    87  	stats := newStats(metricsProvider)
    88  	return &BlockStoreProvider{conf, indexConfig, p, stats}, nil
    89  }
    90  
    91  // Open opens a block store for given ledgerid.
    92  // If a blockstore is not existing, this method creates one
    93  // This method should be invoked only once for a particular ledgerid
    94  func (p *BlockStoreProvider) Open(ledgerid string) (*BlockStore, error) {
    95  	indexStoreHandle := p.leveldbProvider.GetDBHandle(ledgerid)
    96  	return newBlockStore(ledgerid, p.conf, p.indexConfig, indexStoreHandle, p.stats)
    97  }
    98  
    99  // ImportFromSnapshot initializes blockstore from a previously generated snapshot
   100  // Any failure during bootstrapping the blockstore may leave the partial loaded data
   101  // on disk. The consumer, such as peer is expected to keep track of failures and cleanup the
   102  // data explicitly.
   103  func (p *BlockStoreProvider) ImportFromSnapshot(
   104  	ledgerID string,
   105  	snapshotDir string,
   106  	snapshotInfo *SnapshotInfo,
   107  ) error {
   108  	indexStoreHandle := p.leveldbProvider.GetDBHandle(ledgerID)
   109  	if err := bootstrapFromSnapshottedTxIDs(ledgerID, snapshotDir, snapshotInfo, p.conf, indexStoreHandle); err != nil {
   110  		return err
   111  	}
   112  	return nil
   113  }
   114  
   115  // Exists tells whether the BlockStore with given id exists
   116  func (p *BlockStoreProvider) Exists(ledgerid string) (bool, error) {
   117  	exists, err := fileutil.DirExists(p.conf.getLedgerBlockDir(ledgerid))
   118  	return exists, err
   119  }
   120  
   121  // Drop drops blockstore data (block index and blocks directory) for the given ledgerid (channelID).
   122  // It is not an error if the channel does not exist.
   123  // This function is not error safe. If this function returns an error or a crash takes place, it is highly likely
   124  // that the data for this ledger is left in an inconsistent state. Opening the ledger again or reusing the previously
   125  // opened ledger can show unknown behavior.
   126  func (p *BlockStoreProvider) Drop(ledgerid string) error {
   127  	exists, err := p.Exists(ledgerid)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	if !exists {
   132  		return nil
   133  	}
   134  	if err := p.leveldbProvider.Drop(ledgerid); err != nil {
   135  		return err
   136  	}
   137  	if err := os.RemoveAll(p.conf.getLedgerBlockDir(ledgerid)); err != nil {
   138  		return err
   139  	}
   140  	return fileutil.SyncDir(p.conf.getChainsDir())
   141  }
   142  
   143  // List lists the ids of the existing ledgers
   144  func (p *BlockStoreProvider) List() ([]string, error) {
   145  	return fileutil.ListSubdirs(p.conf.getChainsDir())
   146  }
   147  
   148  // Close closes the BlockStoreProvider
   149  func (p *BlockStoreProvider) Close() {
   150  	p.leveldbProvider.Close()
   151  }
   152  
   153  func dataFormatVersion(indexConfig *IndexConfig) string {
   154  	// in version 2.0 we merged three indexable into one `IndexableAttrTxID`
   155  	if indexConfig.Contains(IndexableAttrTxID) {
   156  		return dataformat.CurrentFormat
   157  	}
   158  	return dataformat.PreviousFormat
   159  }