github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/ledger/blockledger/fileledger/factory.go (about)

     1  /*
     2  Copyright hechain. 2022 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package fileledger
     8  
     9  import (
    10  	"os"
    11  	"path/filepath"
    12  	"sync"
    13  
    14  	"github.com/hechain20/hechain/common/ledger/blkstorage"
    15  	"github.com/hechain20/hechain/common/ledger/blockledger"
    16  	"github.com/hechain20/hechain/common/metrics"
    17  	"github.com/hechain20/hechain/orderer/common/filerepo"
    18  )
    19  
    20  //go:generate counterfeiter -o mock/block_store_provider.go --fake-name BlockStoreProvider . blockStoreProvider
    21  type blockStoreProvider interface {
    22  	Open(ledgerid string) (*blkstorage.BlockStore, error)
    23  	Drop(ledgerid string) error
    24  	List() ([]string, error)
    25  	Close()
    26  }
    27  
    28  type fileLedgerFactory struct {
    29  	blkstorageProvider blockStoreProvider
    30  	ledgers            map[string]*FileLedger
    31  	mutex              sync.Mutex
    32  	removeFileRepo     *filerepo.Repo
    33  }
    34  
    35  // GetOrCreate gets an existing ledger (if it exists) or creates it
    36  // if it does not.
    37  func (f *fileLedgerFactory) GetOrCreate(channelID string) (blockledger.ReadWriter, error) {
    38  	f.mutex.Lock()
    39  	defer f.mutex.Unlock()
    40  
    41  	// check cache
    42  	ledger, ok := f.ledgers[channelID]
    43  	if ok {
    44  		return ledger, nil
    45  	}
    46  	// open fresh
    47  	blockStore, err := f.blkstorageProvider.Open(channelID)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  	ledger = NewFileLedger(blockStore)
    52  	f.ledgers[channelID] = ledger
    53  	return ledger, nil
    54  }
    55  
    56  // Remove removes an existing ledger and its indexes. This operation
    57  // is blocking.
    58  func (f *fileLedgerFactory) Remove(channelID string) error {
    59  	f.mutex.Lock()
    60  	defer f.mutex.Unlock()
    61  
    62  	if err := f.removeFileRepo.Save(channelID, []byte{}); err != nil && err != os.ErrExist {
    63  		return err
    64  	}
    65  
    66  	// check cache for open blockstore and, if one exists,
    67  	// shut it down in order to avoid resource contention
    68  	ledger, ok := f.ledgers[channelID]
    69  	if ok {
    70  		ledger.blockStore.Shutdown()
    71  	}
    72  
    73  	err := f.blkstorageProvider.Drop(channelID)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	delete(f.ledgers, channelID)
    79  
    80  	if err := f.removeFileRepo.Remove(channelID); err != nil {
    81  		return err
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  // ChannelIDs returns the channel IDs the factory is aware of.
    88  func (f *fileLedgerFactory) ChannelIDs() []string {
    89  	channelIDs, err := f.blkstorageProvider.List()
    90  	if err != nil {
    91  		logger.Panic(err)
    92  	}
    93  	return channelIDs
    94  }
    95  
    96  // Close releases all resources acquired by the factory.
    97  func (f *fileLedgerFactory) Close() {
    98  	f.blkstorageProvider.Close()
    99  }
   100  
   101  // New creates a new ledger factory
   102  func New(directory string, metricsProvider metrics.Provider) (blockledger.Factory, error) {
   103  	p, err := blkstorage.NewProvider(
   104  		blkstorage.NewConf(directory, -1),
   105  		&blkstorage.IndexConfig{
   106  			AttrsToIndex: []blkstorage.IndexableAttr{blkstorage.IndexableAttrBlockNum},
   107  		},
   108  		metricsProvider,
   109  	)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	fileRepo, err := filerepo.New(filepath.Join(directory, "pendingops"), "remove")
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	factory := &fileLedgerFactory{
   120  		blkstorageProvider: p,
   121  		ledgers:            map[string]*FileLedger{},
   122  		removeFileRepo:     fileRepo,
   123  	}
   124  
   125  	files, err := factory.removeFileRepo.List()
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	for _, fileName := range files {
   130  		channelID := factory.removeFileRepo.FileToBaseName(fileName)
   131  		err = factory.Remove(channelID)
   132  		if err != nil {
   133  			logger.Errorf("Failed to remove channel %s: %s", channelID, err.Error())
   134  			return nil, err
   135  		}
   136  		logger.Infof("Removed channel: %s", channelID)
   137  	}
   138  
   139  	return factory, nil
   140  }