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 }