github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/orderer/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/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  // Iterator returns an Iterator, as specified by a cb.SeekInfo message, and its
    67  // starting block number
    68  func (rl *ramLedger) Iterator(startPosition *ab.SeekPosition) (ledger.Iterator, uint64) {
    69  	var list *simpleList
    70  	switch start := startPosition.Type.(type) {
    71  	case *ab.SeekPosition_Oldest:
    72  		oldest := rl.oldest
    73  		list = &simpleList{
    74  			block:  &cb.Block{Header: &cb.BlockHeader{Number: oldest.block.Header.Number - 1}},
    75  			next:   oldest,
    76  			signal: make(chan struct{}),
    77  		}
    78  		close(list.signal)
    79  	case *ab.SeekPosition_Newest:
    80  		newest := rl.newest
    81  		list = &simpleList{
    82  			block:  &cb.Block{Header: &cb.BlockHeader{Number: newest.block.Header.Number - 1}},
    83  			next:   newest,
    84  			signal: make(chan struct{}),
    85  		}
    86  		close(list.signal)
    87  	case *ab.SeekPosition_Specified:
    88  		oldest := rl.oldest
    89  		specified := start.Specified.Number
    90  		logger.Debugf("Attempting to return block %d", specified)
    91  
    92  		// Note the two +1's here is to accommodate the 'preGenesis' block of ^uint64(0)
    93  		if specified+1 < oldest.block.Header.Number+1 || specified > rl.newest.block.Header.Number+1 {
    94  			logger.Debugf("Returning error iterator because specified seek was %d with oldest %d and newest %d",
    95  				specified, rl.oldest.block.Header.Number, rl.newest.block.Header.Number)
    96  			return &ledger.NotFoundErrorIterator{}, 0
    97  		}
    98  
    99  		if specified == oldest.block.Header.Number {
   100  			list = &simpleList{
   101  				block:  &cb.Block{Header: &cb.BlockHeader{Number: oldest.block.Header.Number - 1}},
   102  				next:   oldest,
   103  				signal: make(chan struct{}),
   104  			}
   105  			close(list.signal)
   106  			break
   107  		}
   108  
   109  		list = oldest
   110  		for {
   111  			if list.block.Header.Number == specified-1 {
   112  				break
   113  			}
   114  			list = list.next // No need for nil check, because of range check above
   115  		}
   116  	}
   117  	cursor := &cursor{list: list}
   118  	blockNum := list.block.Header.Number + 1
   119  
   120  	// If the cursor is for pre-genesis, skip it, the block number wraps
   121  	if blockNum == ^uint64(0) {
   122  		cursor.Next()
   123  		blockNum++
   124  	}
   125  
   126  	return cursor, blockNum
   127  }
   128  
   129  // Height returns the number of blocks on the ledger
   130  func (rl *ramLedger) Height() uint64 {
   131  	return rl.newest.block.Header.Number + 1
   132  }
   133  
   134  // Append appends a new block to the ledger
   135  func (rl *ramLedger) Append(block *cb.Block) error {
   136  	if block.Header.Number != rl.newest.block.Header.Number+1 {
   137  		return fmt.Errorf("Block number should have been %d but was %d",
   138  			rl.newest.block.Header.Number+1, block.Header.Number)
   139  	}
   140  
   141  	if rl.newest.block.Header.Number+1 != 0 { // Skip this check for genesis block insertion
   142  		if !bytes.Equal(block.Header.PreviousHash, rl.newest.block.Header.Hash()) {
   143  			return fmt.Errorf("Block should have had previous hash of %x but was %x",
   144  				rl.newest.block.Header.Hash(), block.Header.PreviousHash)
   145  		}
   146  	}
   147  
   148  	rl.appendBlock(block)
   149  	return nil
   150  }
   151  
   152  func (rl *ramLedger) appendBlock(block *cb.Block) {
   153  	rl.newest.next = &simpleList{
   154  		signal: make(chan struct{}),
   155  		block:  block,
   156  	}
   157  
   158  	lastSignal := rl.newest.signal
   159  	logger.Debugf("Sending signal that block %d has a successor", rl.newest.block.Header.Number)
   160  	rl.newest = rl.newest.next
   161  	close(lastSignal)
   162  
   163  	rl.size++
   164  
   165  	if rl.size > rl.maxSize {
   166  		logger.Debugf("RAM ledger max size about to be exceeded, removing oldest item: %d",
   167  			rl.oldest.block.Header.Number)
   168  		rl.oldest = rl.oldest.next
   169  		rl.size--
   170  	}
   171  }