141 lines
3.3 KiB
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
|
|
}
|