github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/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 at: %s", directory) 51 52 if err := os.MkdirAll(directory, 0700); err != nil { 53 return nil, err 54 } 55 56 ch := newChain(directory) 57 jlf.ledgers[key] = ch 58 return ch, nil 59 } 60 61 // newChain creates a new chain backed by a JSON ledger 62 func newChain(directory string) ledger.ReadWriter { 63 jl := &jsonLedger{ 64 directory: directory, 65 signal: make(chan struct{}), 66 marshaler: &jsonpb.Marshaler{Indent: " "}, 67 } 68 jl.initializeBlockHeight() 69 logger.Debugf("Initialized to block height %d with hash %x", jl.height-1, jl.lastHash) 70 return jl 71 } 72 73 // initializeBlockHeight verifies that all blocks exist between 0 and the block 74 // height, and populates the lastHash 75 func (jl *jsonLedger) initializeBlockHeight() { 76 infos, err := ioutil.ReadDir(jl.directory) 77 if err != nil { 78 logger.Panic(err) 79 } 80 nextNumber := uint64(0) 81 for _, info := range infos { 82 if info.IsDir() { 83 continue 84 } 85 var number uint64 86 _, err := fmt.Sscanf(info.Name(), blockFileFormatString, &number) 87 if err != nil { 88 continue 89 } 90 if number != nextNumber { 91 logger.Panicf("Missing block %d in the chain", nextNumber) 92 } 93 nextNumber++ 94 } 95 jl.height = nextNumber 96 if jl.height == 0 { 97 return 98 } 99 block, found := jl.readBlock(jl.height - 1) 100 if !found { 101 logger.Panicf("Block %d was in directory listing but error reading", jl.height-1) 102 } 103 if block == nil { 104 logger.Panicf("Error reading block %d", jl.height-1) 105 } 106 jl.lastHash = block.Header.Hash() 107 } 108 109 // ChainIDs returns the chain IDs the factory is aware of 110 func (jlf *jsonLedgerFactory) ChainIDs() []string { 111 jlf.mutex.Lock() 112 defer jlf.mutex.Unlock() 113 ids := make([]string, len(jlf.ledgers)) 114 115 i := 0 116 for key := range jlf.ledgers { 117 ids[i] = key 118 i++ 119 } 120 121 return ids 122 } 123 124 // Close is a no-op for the JSON ledger 125 func (jlf *jsonLedgerFactory) Close() { 126 return // nothing to do 127 } 128 129 // New creates a new ledger factory 130 func New(directory string) ledger.Factory { 131 logger.Debugf("Initializing ledger at: %s", directory) 132 if err := os.MkdirAll(directory, 0700); err != nil { 133 logger.Fatalf("Could not create directory %s: %s", directory, err) 134 } 135 136 jlf := &jsonLedgerFactory{ 137 directory: directory, 138 ledgers: make(map[string]ledger.ReadWriter), 139 } 140 141 infos, err := ioutil.ReadDir(jlf.directory) 142 if err != nil { 143 logger.Panicf("Error reading from directory %s while initializing ledger: %s", jlf.directory, err) 144 } 145 146 for _, info := range infos { 147 if !info.IsDir() { 148 continue 149 } 150 var chainID string 151 _, err := fmt.Sscanf(info.Name(), chainDirectoryFormatString, &chainID) 152 if err != nil { 153 continue 154 } 155 jl, err := jlf.GetOrCreate(chainID) 156 if err != nil { 157 logger.Warningf("Failed to initialize chain from %s: %s", chainID, err) 158 continue 159 } 160 jlf.ledgers[chainID] = jl 161 } 162 163 return jlf 164 }