-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This CR implements a store for persisting the writesets produced over the private data. From data perspective, this storage is analogous to the block storage for the block data Change-Id: I43b5349d3671bffa67f7975794e6f1937f99dde5 Signed-off-by: manish <manish.sethi@gmail.com>
- Loading branch information
1 parent
ee12505
commit 5d47989
Showing
8 changed files
with
710 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
Copyright IBM Corp. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
package ledger | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/hyperledger/fabric/protos/ledger/rwset" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestTxPvtData(t *testing.T) { | ||
txPvtData := &TxPvtData{} | ||
assert.False(t, txPvtData.Has("ns", "coll")) | ||
|
||
txPvtData.WriteSet = &rwset.TxPvtReadWriteSet{ | ||
DataModel: rwset.TxReadWriteSet_KV, | ||
NsPvtRwset: []*rwset.NsPvtReadWriteSet{ | ||
&rwset.NsPvtReadWriteSet{ | ||
Namespace: "ns", | ||
CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{ | ||
&rwset.CollectionPvtReadWriteSet{ | ||
CollectionName: "coll-1", | ||
Rwset: []byte("RandomBytes-PvtRWSet-ns1-coll1"), | ||
}, | ||
&rwset.CollectionPvtReadWriteSet{ | ||
CollectionName: "coll-2", | ||
Rwset: []byte("RandomBytes-PvtRWSet-ns1-coll2"), | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
assert.True(t, txPvtData.Has("ns", "coll-1")) | ||
assert.True(t, txPvtData.Has("ns", "coll-2")) | ||
assert.False(t, txPvtData.Has("ns", "coll-3")) | ||
assert.False(t, txPvtData.Has("ns1", "coll-1")) | ||
} | ||
|
||
func TestPvtNsCollFilter(t *testing.T) { | ||
filter := NewPvtNsCollFilter() | ||
filter.Add("ns", "coll-1") | ||
filter.Add("ns", "coll-2") | ||
assert.True(t, filter.Has("ns", "coll-1")) | ||
assert.True(t, filter.Has("ns", "coll-2")) | ||
assert.False(t, filter.Has("ns", "coll-3")) | ||
assert.False(t, filter.Has("ns1", "coll-3")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
Copyright IBM Corp. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package pvtdatastorage | ||
|
||
import ( | ||
"math" | ||
|
||
"github.com/golang/protobuf/proto" | ||
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version" | ||
"github.com/hyperledger/fabric/protos/ledger/rwset" | ||
) | ||
|
||
var ( | ||
pendingCommitKey = []byte{0} | ||
lastCommittedBlkkey = []byte{1} | ||
pvtDataKeyPrefix = []byte{2} | ||
|
||
emptyValue = []byte{} | ||
) | ||
|
||
func encodePK(blockNum uint64, tranNum uint64) blkTranNumKey { | ||
return append(pvtDataKeyPrefix, version.NewHeight(blockNum, tranNum).ToBytes()...) | ||
} | ||
|
||
func decodePK(key blkTranNumKey) (blockNum uint64, tranNum uint64) { | ||
height, _ := version.NewHeightFromBytes(key[1:]) | ||
return height.BlockNum, height.TxNum | ||
} | ||
|
||
func getKeysForRangeScanByBlockNum(blockNum uint64) (startKey []byte, endKey []byte) { | ||
startKey = encodePK(blockNum, 0) | ||
endKey = encodePK(blockNum, math.MaxUint64) | ||
return | ||
} | ||
|
||
func encodePvtRwSet(txPvtRwSet *rwset.TxPvtReadWriteSet) ([]byte, error) { | ||
return proto.Marshal(txPvtRwSet) | ||
} | ||
|
||
func decodePvtRwSet(encodedBytes []byte) (*rwset.TxPvtReadWriteSet, error) { | ||
writeset := &rwset.TxPvtReadWriteSet{} | ||
return writeset, proto.Unmarshal(encodedBytes, writeset) | ||
} | ||
|
||
func encodeBlockNum(blockNum uint64) []byte { | ||
return proto.EncodeVarint(blockNum) | ||
} | ||
|
||
func decodeBlockNum(blockNumBytes []byte) uint64 { | ||
s, _ := proto.DecodeVarint(blockNumBytes) | ||
return s | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
Copyright IBM Corp. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package pvtdatastorage | ||
|
||
import ( | ||
"github.com/hyperledger/fabric/core/ledger" | ||
) | ||
|
||
// Provider provides handle to specific 'Store' that in turn manages | ||
// private write sets for a ledger | ||
type Provider interface { | ||
OpenStore(id string) (Store, error) | ||
Close() | ||
} | ||
|
||
// Store manages the permanent storage of private write sets for a ledger | ||
// Beacsue the pvt data is supposed to be in sync with the blocks in the | ||
// ledger, both should logically happen in an atomic operation. In order | ||
// to accomplish this, an implementation of this store should provide | ||
// support for a two-phase like commit/rollback capability. | ||
// The expected use is such that - first the private data will be given to | ||
// this store (via `Prepare` funtion) and then the block is appended to the block storage. | ||
// Finally, one of the functions `Commit` or `Rollback` is invoked on this store based | ||
// on whether the block was written successfully or not. The store implementation | ||
// is expected to survive a server crash between the call to `Prepare` and `Commit`/`Rollback` | ||
type Store interface { | ||
// GetPvtDataByBlockNum returns only the pvt data corresponding to the given block number | ||
// The pvt data is filtered by the list of 'ns/collections' supplied in the filter | ||
// A nil filter does not filter any results | ||
GetPvtDataByBlockNum(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error) | ||
// Prepare prepares the Store for commiting the pvt data. This call does not commit the pvt data. | ||
// Subsequently, the caller is expected to call either `Commit` or `Rollback` function. | ||
// Return from this should ensure that enough preparation is done such that `Commit` function invoked afterwards | ||
// can commit the data and the store is capable of surviving a crash between this function call and the next | ||
// invoke to the `Commit` | ||
Prepare(blockNum uint64, pvtData []*ledger.TxPvtData) error | ||
// Commit commits the pvt data passed in the previous invoke to the `Prepare` function | ||
Commit() error | ||
// Rollback rolls back the pvt data passed in the previous invoke to the `Prepare` function | ||
Rollback() error | ||
// IsEmpty returns true if the store does not have any block committed yet | ||
IsEmpty() (bool, error) | ||
// LastCommittedBlock returns the last committed blocknum | ||
LastCommittedBlock() (uint64, error) | ||
// HasPendingBatch returns if the store has a pending batch | ||
HasPendingBatch() (bool, error) | ||
// Shutdown stops the store | ||
Shutdown() | ||
} | ||
|
||
// ErrIllegalCall is to be thrown by a store impl if the store does not expect a call to Prepare/Commit/Rollback | ||
type ErrIllegalCall struct { | ||
msg string | ||
} | ||
|
||
func (err *ErrIllegalCall) Error() string { | ||
return err.msg | ||
} | ||
|
||
// ErrIllegalArgs is to be thrown by a store impl if the args passed are not allowed | ||
type ErrIllegalArgs struct { | ||
msg string | ||
} | ||
|
||
func (err *ErrIllegalArgs) Error() string { | ||
return err.msg | ||
} | ||
|
||
// ErrOutOfRange is to be thrown for the request for the data that is not yet committed | ||
type ErrOutOfRange struct { | ||
msg string | ||
} | ||
|
||
func (err *ErrOutOfRange) Error() string { | ||
return err.msg | ||
} |
Oops, something went wrong.