github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/orderer/common/ledger/ram/impl.go (about) 1 /* 2 Copyright IBM Corp. 2016 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 ramledger 18 19 import ( 20 "bytes" 21 "fmt" 22 23 "github.com/hyperledger/fabric/orderer/common/ledger" 24 cb "github.com/hyperledger/fabric/protos/common" 25 ab "github.com/hyperledger/fabric/protos/orderer" 26 "github.com/op/go-logging" 27 ) 28 29 var logger = logging.MustGetLogger("orderer/ramledger") 30 31 type cursor struct { 32 list *simpleList 33 } 34 35 type simpleList struct { 36 next *simpleList 37 signal chan struct{} 38 block *cb.Block 39 } 40 41 type ramLedger struct { 42 maxSize int 43 size int 44 oldest *simpleList 45 newest *simpleList 46 } 47 48 // Next blocks until there is a new block available, or returns an error if the 49 // next block is no longer retrievable 50 func (cu *cursor) Next() (*cb.Block, cb.Status) { 51 // This only loops once, as signal reading indicates non-nil next 52 for { 53 if cu.list.next != nil { 54 cu.list = cu.list.next 55 return cu.list.block, cb.Status_SUCCESS 56 } 57 <-cu.list.signal 58 } 59 } 60 61 // ReadyChan supplies a channel which will block until Next will not block 62 func (cu *cursor) ReadyChan() <-chan struct{} { 63 return cu.list.signal 64 } 65 66 // Close does nothing 67 func (cu *cursor) Close() {} 68 69 // Iterator returns an Iterator, as specified by a cb.SeekInfo message, and its 70 // starting block number 71 func (rl *ramLedger) Iterator(startPosition *ab.SeekPosition) (ledger.Iterator, uint64) { 72 var list *simpleList 73 switch start := startPosition.Type.(type) { 74 case *ab.SeekPosition_Oldest: 75 oldest := rl.oldest 76 list = &simpleList{ 77 block: &cb.Block{Header: &cb.BlockHeader{Number: oldest.block.Header.Number - 1}}, 78 next: oldest, 79 signal: make(chan struct{}), 80 } 81 close(list.signal) 82 case *ab.SeekPosition_Newest: 83 newest := rl.newest 84 list = &simpleList{ 85 block: &cb.Block{Header: &cb.BlockHeader{Number: newest.block.Header.Number - 1}}, 86 next: newest, 87 signal: make(chan struct{}), 88 } 89 close(list.signal) 90 case *ab.SeekPosition_Specified: 91 oldest := rl.oldest 92 specified := start.Specified.Number 93 logger.Debugf("Attempting to return block %d", specified) 94 95 // Note the two +1's here is to accommodate the 'preGenesis' block of ^uint64(0) 96 if specified+1 < oldest.block.Header.Number+1 || specified > rl.newest.block.Header.Number+1 { 97 logger.Debugf("Returning error iterator because specified seek was %d with oldest %d and newest %d", 98 specified, rl.oldest.block.Header.Number, rl.newest.block.Header.Number) 99 return &ledger.NotFoundErrorIterator{}, 0 100 } 101 102 if specified == oldest.block.Header.Number { 103 list = &simpleList{ 104 block: &cb.Block{Header: &cb.BlockHeader{Number: oldest.block.Header.Number - 1}}, 105 next: oldest, 106 signal: make(chan struct{}), 107 } 108 close(list.signal) 109 break 110 } 111 112 list = oldest 113 for { 114 if list.block.Header.Number == specified-1 { 115 break 116 } 117 list = list.next // No need for nil check, because of range check above 118 } 119 } 120 cursor := &cursor{list: list} 121 blockNum := list.block.Header.Number + 1 122 123 // If the cursor is for pre-genesis, skip it, the block number wraps 124 if blockNum == ^uint64(0) { 125 cursor.Next() 126 blockNum++ 127 } 128 129 return cursor, blockNum 130 } 131 132 // Height returns the number of blocks on the ledger 133 func (rl *ramLedger) Height() uint64 { 134 return rl.newest.block.Header.Number + 1 135 } 136 137 // Append appends a new block to the ledger 138 func (rl *ramLedger) Append(block *cb.Block) error { 139 if block.Header.Number != rl.newest.block.Header.Number+1 { 140 return fmt.Errorf("Block number should have been %d but was %d", 141 rl.newest.block.Header.Number+1, block.Header.Number) 142 } 143 144 if rl.newest.block.Header.Number+1 != 0 { // Skip this check for genesis block insertion 145 if !bytes.Equal(block.Header.PreviousHash, rl.newest.block.Header.Hash()) { 146 return fmt.Errorf("Block should have had previous hash of %x but was %x", 147 rl.newest.block.Header.Hash(), block.Header.PreviousHash) 148 } 149 } 150 151 rl.appendBlock(block) 152 return nil 153 } 154 155 func (rl *ramLedger) appendBlock(block *cb.Block) { 156 rl.newest.next = &simpleList{ 157 signal: make(chan struct{}), 158 block: block, 159 } 160 161 lastSignal := rl.newest.signal 162 logger.Debugf("Sending signal that block %d has a successor", rl.newest.block.Header.Number) 163 rl.newest = rl.newest.next 164 close(lastSignal) 165 166 rl.size++ 167 168 if rl.size > rl.maxSize { 169 logger.Debugf("RAM ledger max size about to be exceeded, removing oldest item: %d", 170 rl.oldest.block.Header.Number) 171 rl.oldest = rl.oldest.next 172 rl.size-- 173 } 174 }