github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/orderer/ledger/json/factory.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8                   http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package jsonledger
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"path/filepath"
    24  	"sync"
    25  
    26  	"github.com/golang/protobuf/jsonpb"
    27  	"github.com/hyperledger/fabric/orderer/ledger"
    28  )
    29  
    30  type jsonLedgerFactory struct {
    31  	directory string
    32  	ledgers   map[string]ledger.ReadWriter
    33  	mutex     sync.Mutex
    34  }
    35  
    36  // GetOrCreate gets an existing ledger (if it exists) or creates it if it does not
    37  func (jlf *jsonLedgerFactory) GetOrCreate(chainID string) (ledger.ReadWriter, error) {
    38  	jlf.mutex.Lock()
    39  	defer jlf.mutex.Unlock()
    40  
    41  	key := chainID
    42  
    43  	l, ok := jlf.ledgers[key]
    44  	if ok {
    45  		return l, nil
    46  	}
    47  
    48  	directory := filepath.Join(jlf.directory, fmt.Sprintf(chainDirectoryFormatString, chainID))
    49  
    50  	logger.Debugf("Initializing chain %s at: %s", chainID, directory)
    51  
    52  	if err := os.MkdirAll(directory, 0700); err != nil {
    53  		logger.Warningf("Failed initializing chain %s: %s", chainID, err)
    54  		return nil, err
    55  	}
    56  
    57  	ch := newChain(directory)
    58  	jlf.ledgers[key] = ch
    59  	return ch, nil
    60  }
    61  
    62  // newChain creates a new chain backed by a JSON ledger
    63  func newChain(directory string) ledger.ReadWriter {
    64  	jl := &jsonLedger{
    65  		directory: directory,
    66  		signal:    make(chan struct{}),
    67  		marshaler: &jsonpb.Marshaler{Indent: "  "},
    68  	}
    69  	jl.initializeBlockHeight()
    70  	logger.Debugf("Initialized to block height %d with hash %x", jl.height-1, jl.lastHash)
    71  	return jl
    72  }
    73  
    74  // initializeBlockHeight verifies that all blocks exist between 0 and the block
    75  // height, and populates the lastHash
    76  func (jl *jsonLedger) initializeBlockHeight() {
    77  	infos, err := ioutil.ReadDir(jl.directory)
    78  	if err != nil {
    79  		logger.Panic(err)
    80  	}
    81  	nextNumber := uint64(0)
    82  	for _, info := range infos {
    83  		if info.IsDir() {
    84  			continue
    85  		}
    86  		var number uint64
    87  		_, err := fmt.Sscanf(info.Name(), blockFileFormatString, &number)
    88  		if err != nil {
    89  			continue
    90  		}
    91  		if number != nextNumber {
    92  			logger.Panicf("Missing block %d in the chain", nextNumber)
    93  		}
    94  		nextNumber++
    95  	}
    96  	jl.height = nextNumber
    97  	if jl.height == 0 {
    98  		return
    99  	}
   100  	block, found := jl.readBlock(jl.height - 1)
   101  	if !found {
   102  		logger.Panicf("Block %d was in directory listing but error reading", jl.height-1)
   103  	}
   104  	if block == nil {
   105  		logger.Panicf("Error reading block %d", jl.height-1)
   106  	}
   107  	jl.lastHash = block.Header.Hash()
   108  }
   109  
   110  // ChainIDs returns the chain IDs the factory is aware of
   111  func (jlf *jsonLedgerFactory) ChainIDs() []string {
   112  	jlf.mutex.Lock()
   113  	defer jlf.mutex.Unlock()
   114  	ids := make([]string, len(jlf.ledgers))
   115  
   116  	i := 0
   117  	for key := range jlf.ledgers {
   118  		ids[i] = key
   119  		i++
   120  	}
   121  
   122  	return ids
   123  }
   124  
   125  // Close is a no-op for the JSON ledger
   126  func (jlf *jsonLedgerFactory) Close() {
   127  	return // nothing to do
   128  }
   129  
   130  // New creates a new ledger factory
   131  func New(directory string) ledger.Factory {
   132  	logger.Debugf("Initializing ledger at: %s", directory)
   133  	if err := os.MkdirAll(directory, 0700); err != nil {
   134  		logger.Panicf("Could not create directory %s: %s", directory, err)
   135  	}
   136  
   137  	jlf := &jsonLedgerFactory{
   138  		directory: directory,
   139  		ledgers:   make(map[string]ledger.ReadWriter),
   140  	}
   141  
   142  	infos, err := ioutil.ReadDir(jlf.directory)
   143  	if err != nil {
   144  		logger.Panicf("Error reading from directory %s while initializing ledger: %s", jlf.directory, err)
   145  	}
   146  
   147  	for _, info := range infos {
   148  		if !info.IsDir() {
   149  			continue
   150  		}
   151  		var chainID string
   152  		_, err := fmt.Sscanf(info.Name(), chainDirectoryFormatString, &chainID)
   153  		if err != nil {
   154  			continue
   155  		}
   156  		jlf.GetOrCreate(chainID)
   157  	}
   158  
   159  	return jlf
   160  }