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 }