github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/common/ledger/blkstorage/blockstore_provider.go (about)

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