Skip to content

Commit c7badc3

Browse files
committed
Raw ledger implementation
Raw ledger provides basic functionality for storing and retrieving blocks. This is intended to be used by an orderer service https://jira.hyperledger.org/browse/FAB-56 Change-Id: I3fb733f5be53b6f630c20554ba4e362540b8f55a Signed-off-by: manish <[email protected]>
1 parent bb413ce commit c7badc3

18 files changed

+531
-134
lines changed

core/chaincode/handler.go

+18-15
Original file line numberDiff line numberDiff line change
@@ -716,16 +716,18 @@ func (handler *Handler) handleRangeQueryState(msg *pb.ChaincodeMessage) {
716716

717717
handler.putRangeQueryIterator(txContext, iterID, rangeIter)
718718

719-
hasNext := rangeIter.Next()
720-
721719
var keysAndValues []*pb.RangeQueryStateKeyValue
722720
var i = uint32(0)
723-
for ; hasNext && i < maxRangeQueryStateLimit; i++ {
724-
qresult, err := rangeIter.Get()
721+
var qresult ledger.QueryResult
722+
for ; i < maxRangeQueryStateLimit; i++ {
723+
qresult, err := rangeIter.Next()
725724
if err != nil {
726725
chaincodeLogger.Errorf("Failed to get query result from iterator. Sending %s", pb.ChaincodeMessage_ERROR)
727726
return
728727
}
728+
if qresult == nil {
729+
break
730+
}
729731
//PDMP - let it panic if not KV
730732
kv := qresult.(ledger.KV)
731733
// Decrypt the data if the confidential is enabled
@@ -742,16 +744,14 @@ func (handler *Handler) handleRangeQueryState(msg *pb.ChaincodeMessage) {
742744
}
743745
keyAndValue := pb.RangeQueryStateKeyValue{Key: kv.Key, Value: decryptedValue}
744746
keysAndValues = append(keysAndValues, &keyAndValue)
745-
746-
hasNext = rangeIter.Next()
747747
}
748748

749-
if !hasNext {
749+
if qresult != nil {
750750
rangeIter.Close()
751751
handler.deleteRangeQueryIterator(txContext, iterID)
752752
}
753753

754-
payload := &pb.RangeQueryStateResponse{KeysAndValues: keysAndValues, HasMore: hasNext, ID: iterID}
754+
payload := &pb.RangeQueryStateResponse{KeysAndValues: keysAndValues, HasMore: qresult != nil, ID: iterID}
755755
payloadBytes, err := proto.Marshal(payload)
756756
if err != nil {
757757
rangeIter.Close()
@@ -827,13 +827,18 @@ func (handler *Handler) handleRangeQueryStateNext(msg *pb.ChaincodeMessage) {
827827

828828
var keysAndValues []*pb.RangeQueryStateKeyValue
829829
var i = uint32(0)
830-
hasNext := true
831-
for ; hasNext && i < maxRangeQueryStateLimit; i++ {
832-
qresult, err := rangeIter.Get()
830+
831+
var qresult ledger.QueryResult
832+
var err error
833+
for ; i < maxRangeQueryStateLimit; i++ {
834+
qresult, err = rangeIter.Next()
833835
if err != nil {
834836
chaincodeLogger.Errorf("Failed to get query result from iterator. Sending %s", pb.ChaincodeMessage_ERROR)
835837
return
836838
}
839+
if qresult != nil {
840+
break
841+
}
837842
//PDMP - let it panic if not KV
838843
kv := qresult.(ledger.KV)
839844
// Decrypt the data if the confidential is enabled
@@ -850,16 +855,14 @@ func (handler *Handler) handleRangeQueryStateNext(msg *pb.ChaincodeMessage) {
850855
}
851856
keyAndValue := pb.RangeQueryStateKeyValue{Key: kv.Key, Value: decryptedValue}
852857
keysAndValues = append(keysAndValues, &keyAndValue)
853-
854-
hasNext = rangeIter.Next()
855858
}
856859

857-
if !hasNext {
860+
if qresult != nil {
858861
rangeIter.Close()
859862
handler.deleteRangeQueryIterator(txContext, rangeQueryStateNext.ID)
860863
}
861864

862-
payload := &pb.RangeQueryStateResponse{KeysAndValues: keysAndValues, HasMore: hasNext, ID: rangeQueryStateNext.ID}
865+
payload := &pb.RangeQueryStateResponse{KeysAndValues: keysAndValues, HasMore: qresult != nil, ID: rangeQueryStateNext.ID}
863866
payloadBytes, err := proto.Marshal(payload)
864867
if err != nil {
865868
rangeIter.Close()

core/ledger/blkstorage/blockstorage.go

+27-1
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,41 @@ limitations under the License.
1717
package blkstorage
1818

1919
import (
20+
"errors"
21+
2022
"github.com/hyperledger/fabric/core/ledger"
2123
"github.com/hyperledger/fabric/protos"
2224
)
2325

26+
// IndexableAttr represents an indexable attribute
27+
type IndexableAttr string
28+
29+
// constants for indexable attributes
30+
const (
31+
IndexableAttrBlockNum = IndexableAttr("BlockNum")
32+
IndexableAttrBlockHash = IndexableAttr("BlockHash")
33+
IndexableAttrTxID = IndexableAttr("TxID")
34+
)
35+
36+
// IndexConfig - a configuration that includes a list of attributes that should be indexed
37+
type IndexConfig struct {
38+
AttrsToIndex []IndexableAttr
39+
}
40+
41+
var (
42+
// ErrNotFoundInIndex is used to indicate missing entry in the index
43+
ErrNotFoundInIndex = errors.New("Entry not found in index")
44+
// ErrAttrNotIndexed is used to indicate that an attribute is not indexed
45+
ErrAttrNotIndexed = errors.New("Attribute not indexed")
46+
)
47+
2448
// BlockStore - an interface for persisting and retrieving blocks
49+
// An implementation of this interface is expected to take an argument
50+
// of type `IndexConfig` which configures the block store on what items should be indexed
2551
type BlockStore interface {
2652
AddBlock(block *protos.Block2) error
2753
GetBlockchainInfo() (*protos.BlockchainInfo, error)
28-
RetrieveBlocks(startNum uint64, endNum uint64) (ledger.ResultsIterator, error)
54+
RetrieveBlocks(startNum uint64) (ledger.ResultsIterator, error)
2955
RetrieveBlockByHash(blockHash []byte) (*protos.Block2, error)
3056
RetrieveBlockByNumber(blockNum uint64) (*protos.Block2, error)
3157
RetrieveTxByID(txID string) (*protos.Transaction2, error)

core/ledger/blkstorage/fsblkstorage/block_stream.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ func (s *blockStream) nextBlockBytesAndPlacementInfo() ([]byte, *blockPlacementI
166166
return nil, nil, err
167167
}
168168
logger.Debugf("blockbytes [%d] read from file [%d]", len(blockBytes), s.currentFileNum)
169-
if blockBytes == nil && s.currentFileNum < s.endFileNum {
169+
if blockBytes == nil && (s.currentFileNum < s.endFileNum || s.endFileNum < 0) {
170170
logger.Debugf("current file [%d] exhausted. Moving to next file", s.currentFileNum)
171171
if err = s.moveToNextBlockfileStream(); err != nil {
172172
return nil, nil, err

core/ledger/blkstorage/fsblkstorage/blockfile_mgr.go

+36-29
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ package fsblkstorage
1818

1919
import (
2020
"fmt"
21+
"sync"
2122
"sync/atomic"
2223

2324
"github.com/golang/protobuf/proto"
25+
"github.com/hyperledger/fabric/core/ledger/blkstorage"
2426
"github.com/hyperledger/fabric/core/ledger/util"
2527
"github.com/hyperledger/fabric/core/ledger/util/db"
2628
"github.com/hyperledger/fabric/protos"
@@ -46,11 +48,12 @@ type blockfileMgr struct {
4648
defaultCF *gorocksdb.ColumnFamilyHandle
4749
index index
4850
cpInfo *checkpointInfo
51+
cpInfoCond *sync.Cond
4952
currentFileWriter *blockfileWriter
5053
bcInfo atomic.Value
5154
}
5255

53-
func newBlockfileMgr(conf *Conf) *blockfileMgr {
56+
func newBlockfileMgr(conf *Conf, indexConfig *blkstorage.IndexConfig) *blockfileMgr {
5457
rootDir := conf.blockfilesDir
5558
_, err := util.CreateDirIfMissing(rootDir)
5659
if err != nil {
@@ -69,7 +72,7 @@ func newBlockfileMgr(conf *Conf) *blockfileMgr {
6972
panic(fmt.Sprintf("Could not save next block file info to db: %s", err))
7073
}
7174
}
72-
updateCPInfo(conf, cpInfo)
75+
syncCPInfoFromFS(conf, cpInfo)
7376
currentFileWriter, err := newBlockfileWriter(deriveBlockfilePath(rootDir, cpInfo.latestFileChunkSuffixNum))
7477
if err != nil {
7578
panic(fmt.Sprintf("Could not open writer to current file: %s", err))
@@ -79,9 +82,10 @@ func newBlockfileMgr(conf *Conf) *blockfileMgr {
7982
panic(fmt.Sprintf("Could not truncate current file to known size in db: %s", err))
8083
}
8184

82-
mgr.index = newBlockIndex(db, db.GetCFHandle(blockIndexCF))
85+
mgr.index = newBlockIndex(indexConfig, db, db.GetCFHandle(blockIndexCF))
8386
mgr.cpInfo = cpInfo
8487
mgr.currentFileWriter = currentFileWriter
88+
mgr.cpInfoCond = sync.NewCond(&sync.Mutex{})
8589
mgr.syncIndex()
8690

8791
// init BlockchainInfo
@@ -119,7 +123,7 @@ func initDB(conf *Conf) *db.DB {
119123
return dbInst
120124
}
121125

122-
func updateCPInfo(conf *Conf, cpInfo *checkpointInfo) {
126+
func syncCPInfoFromFS(conf *Conf, cpInfo *checkpointInfo) {
123127
logger.Debugf("Starting checkpoint=%s", cpInfo)
124128
rootDir := conf.blockfilesDir
125129
filePath := deriveBlockfilePath(rootDir, cpInfo.latestFileChunkSuffixNum)
@@ -156,23 +160,24 @@ func (mgr *blockfileMgr) close() {
156160
}
157161

158162
func (mgr *blockfileMgr) moveToNextFile() {
159-
nextFileInfo := &checkpointInfo{
163+
cpInfo := &checkpointInfo{
160164
latestFileChunkSuffixNum: mgr.cpInfo.latestFileChunkSuffixNum + 1,
161-
latestFileChunksize: 0}
165+
latestFileChunksize: 0,
166+
lastBlockNumber: mgr.cpInfo.lastBlockNumber}
162167

163168
nextFileWriter, err := newBlockfileWriter(
164-
deriveBlockfilePath(mgr.rootDir, nextFileInfo.latestFileChunkSuffixNum))
169+
deriveBlockfilePath(mgr.rootDir, cpInfo.latestFileChunkSuffixNum))
165170

166171
if err != nil {
167172
panic(fmt.Sprintf("Could not open writer to next file: %s", err))
168173
}
169174
mgr.currentFileWriter.close()
170-
err = mgr.saveCurrentInfo(nextFileInfo, true)
175+
err = mgr.saveCurrentInfo(cpInfo, true)
171176
if err != nil {
172177
panic(fmt.Sprintf("Could not save next block file info to db: %s", err))
173178
}
174-
mgr.cpInfo = nextFileInfo
175179
mgr.currentFileWriter = nextFileWriter
180+
mgr.updateCheckpoint(cpInfo)
176181
}
177182

178183
func (mgr *blockfileMgr) addBlock(block *protos.Block2) error {
@@ -207,26 +212,30 @@ func (mgr *blockfileMgr) addBlock(block *protos.Block2) error {
207212
return fmt.Errorf("Error while appending block to file: %s", err)
208213
}
209214

210-
mgr.cpInfo.latestFileChunksize += totalBytesToAppend
211-
mgr.cpInfo.lastBlockNumber++
212-
err = mgr.saveCurrentInfo(mgr.cpInfo, false)
213-
if err != nil {
214-
mgr.cpInfo.latestFileChunksize -= totalBytesToAppend
215-
truncateErr := mgr.currentFileWriter.truncateFile(mgr.cpInfo.latestFileChunksize)
215+
currentCPInfo := mgr.cpInfo
216+
newCPInfo := &checkpointInfo{
217+
latestFileChunkSuffixNum: currentCPInfo.latestFileChunkSuffixNum,
218+
latestFileChunksize: currentCPInfo.latestFileChunksize + totalBytesToAppend,
219+
lastBlockNumber: currentCPInfo.lastBlockNumber + 1}
220+
if err = mgr.saveCurrentInfo(newCPInfo, false); err != nil {
221+
truncateErr := mgr.currentFileWriter.truncateFile(currentCPInfo.latestFileChunksize)
216222
if truncateErr != nil {
217223
panic(fmt.Sprintf("Error in truncating current file to known size after an error in saving checkpoint info: %s", err))
218224
}
219225
return fmt.Errorf("Error while saving current file info to db: %s", err)
220226
}
221-
blockFLP := &fileLocPointer{fileSuffixNum: mgr.cpInfo.latestFileChunkSuffixNum}
227+
228+
blockFLP := &fileLocPointer{fileSuffixNum: newCPInfo.latestFileChunkSuffixNum}
222229
blockFLP.offset = currentOffset
223230
// shift the txoffset because we prepend length of bytes before block bytes
224231
for i := 0; i < len(txOffsets); i++ {
225232
txOffsets[i] += len(blockBytesEncodedLen)
226233
}
227234
mgr.index.indexBlock(&blockIdxInfo{
228-
blockNum: mgr.cpInfo.lastBlockNumber, blockHash: blockHash,
235+
blockNum: newCPInfo.lastBlockNumber, blockHash: blockHash,
229236
flp: blockFLP, txOffsets: txOffsets})
237+
238+
mgr.updateCheckpoint(newCPInfo)
230239
mgr.updateBlockchainInfo(blockHash, block)
231240
return nil
232241
}
@@ -291,6 +300,14 @@ func (mgr *blockfileMgr) getBlockchainInfo() *protos.BlockchainInfo {
291300
return mgr.bcInfo.Load().(*protos.BlockchainInfo)
292301
}
293302

303+
func (mgr *blockfileMgr) updateCheckpoint(cpInfo *checkpointInfo) {
304+
mgr.cpInfoCond.L.Lock()
305+
defer mgr.cpInfoCond.L.Unlock()
306+
mgr.cpInfo = cpInfo
307+
logger.Debugf("Broadcasting about update checkpointInfo: %s", cpInfo)
308+
mgr.cpInfoCond.Broadcast()
309+
}
310+
294311
func (mgr *blockfileMgr) updateBlockchainInfo(latestBlockHash []byte, latestBlock *protos.Block2) {
295312
currentBCInfo := mgr.getBlockchainInfo()
296313
newBCInfo := &protos.BlockchainInfo{
@@ -328,18 +345,8 @@ func (mgr *blockfileMgr) retrieveSerBlockByNumber(blockNum uint64) (*protos.SerB
328345
return mgr.fetchSerBlock(loc)
329346
}
330347

331-
func (mgr *blockfileMgr) retrieveBlocks(startNum uint64, endNum uint64) (*BlocksItr, error) {
332-
var lp *fileLocPointer
333-
var err error
334-
if lp, err = mgr.index.getBlockLocByBlockNum(startNum); err != nil {
335-
return nil, err
336-
}
337-
var stream *blockStream
338-
if stream, err = newBlockStream(mgr.rootDir, lp.fileSuffixNum,
339-
int64(lp.offset), mgr.cpInfo.latestFileChunkSuffixNum); err != nil {
340-
return nil, err
341-
}
342-
return newBlockItr(stream, int(endNum-startNum)+1), nil
348+
func (mgr *blockfileMgr) retrieveBlocks(startNum uint64) (*BlocksItr, error) {
349+
return newBlockItr(mgr, startNum), nil
343350
}
344351

345352
func (mgr *blockfileMgr) retrieveTransactionByID(txID string) (*protos.Transaction2, error) {

core/ledger/blkstorage/fsblkstorage/blockfile_mgr_test.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,18 @@ func TestBlockfileMgrBlockIterator(t *testing.T) {
103103

104104
func testBlockfileMgrBlockIterator(t *testing.T, blockfileMgr *blockfileMgr,
105105
firstBlockNum int, lastBlockNum int, expectedBlocks []*protos.Block2) {
106-
itr, err := blockfileMgr.retrieveBlocks(uint64(firstBlockNum), uint64(lastBlockNum))
106+
itr, err := blockfileMgr.retrieveBlocks(uint64(firstBlockNum))
107107
defer itr.Close()
108108
testutil.AssertNoError(t, err, "Error while getting blocks iterator")
109109
numBlocksItrated := 0
110-
for ; itr.Next(); numBlocksItrated++ {
111-
block, err := itr.Get()
110+
for {
111+
block, err := itr.Next()
112112
testutil.AssertNoError(t, err, fmt.Sprintf("Error while getting block number [%d] from iterator", numBlocksItrated))
113113
testutil.AssertEquals(t, block.(*BlockHolder).GetBlock(), expectedBlocks[numBlocksItrated])
114+
numBlocksItrated++
115+
if numBlocksItrated == lastBlockNum-firstBlockNum+1 {
116+
break
117+
}
114118
}
115119
testutil.AssertEquals(t, numBlocksItrated, lastBlockNum-firstBlockNum+1)
116120
}

0 commit comments

Comments
 (0)