go_study/fabric-main/common/ledger/blockledger/fileledger/factory.go

141 lines
3.3 KiB
Go

/*
Copyright IBM Corp. 2016 All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package fileledger
import (
"os"
"path/filepath"
"sync"
"github.com/hyperledger/fabric/common/ledger/blkstorage"
"github.com/hyperledger/fabric/common/ledger/blockledger"
"github.com/hyperledger/fabric/common/metrics"
"github.com/hyperledger/fabric/orderer/common/filerepo"
)
//go:generate counterfeiter -o mock/block_store_provider.go --fake-name BlockStoreProvider . blockStoreProvider
type blockStoreProvider interface {
Open(ledgerid string) (*blkstorage.BlockStore, error)
Drop(ledgerid string) error
List() ([]string, error)
Close()
}
type fileLedgerFactory struct {
blkstorageProvider blockStoreProvider
ledgers map[string]*FileLedger
mutex sync.Mutex
removeFileRepo *filerepo.Repo
}
// GetOrCreate gets an existing ledger (if it exists) or creates it
// if it does not.
func (f *fileLedgerFactory) GetOrCreate(channelID string) (blockledger.ReadWriter, error) {
f.mutex.Lock()
defer f.mutex.Unlock()
// check cache
ledger, ok := f.ledgers[channelID]
if ok {
return ledger, nil
}
// open fresh
blockStore, err := f.blkstorageProvider.Open(channelID)
if err != nil {
return nil, err
}
ledger = NewFileLedger(blockStore)
f.ledgers[channelID] = ledger
return ledger, nil
}
// Remove removes an existing ledger and its indexes. This operation
// is blocking.
func (f *fileLedgerFactory) Remove(channelID string) error {
f.mutex.Lock()
defer f.mutex.Unlock()
if err := f.removeFileRepo.Save(channelID, []byte{}); err != nil && err != os.ErrExist {
return err
}
// check cache for open blockstore and, if one exists,
// shut it down in order to avoid resource contention
ledger, ok := f.ledgers[channelID]
if ok {
ledger.blockStore.Shutdown()
}
err := f.blkstorageProvider.Drop(channelID)
if err != nil {
return err
}
delete(f.ledgers, channelID)
if err := f.removeFileRepo.Remove(channelID); err != nil {
return err
}
return nil
}
// ChannelIDs returns the channel IDs the factory is aware of.
func (f *fileLedgerFactory) ChannelIDs() []string {
channelIDs, err := f.blkstorageProvider.List()
if err != nil {
logger.Panic(err)
}
return channelIDs
}
// Close releases all resources acquired by the factory.
func (f *fileLedgerFactory) Close() {
f.blkstorageProvider.Close()
}
// New creates a new ledger factory
func New(directory string, metricsProvider metrics.Provider) (blockledger.Factory, error) {
p, err := blkstorage.NewProvider(
blkstorage.NewConf(directory, -1),
&blkstorage.IndexConfig{
AttrsToIndex: []blkstorage.IndexableAttr{blkstorage.IndexableAttrBlockNum},
},
metricsProvider,
)
if err != nil {
return nil, err
}
fileRepo, err := filerepo.New(filepath.Join(directory, "pendingops"), "remove")
if err != nil {
return nil, err
}
factory := &fileLedgerFactory{
blkstorageProvider: p,
ledgers: map[string]*FileLedger{},
removeFileRepo: fileRepo,
}
files, err := factory.removeFileRepo.List()
if err != nil {
return nil, err
}
for _, fileName := range files {
channelID := factory.removeFileRepo.FileToBaseName(fileName)
err = factory.Remove(channelID)
if err != nil {
logger.Errorf("Failed to remove channel %s: %s", channelID, err.Error())
return nil, err
}
logger.Infof("Removed channel: %s", channelID)
}
return factory, nil
}