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 }