Skip to content

Commit 74eeb66

Browse files
committed
FAB-1585 Refactor History to enable LevelDB
The purpose of this refactor is to create a common interface and to isolate the db implementation, so that we can enable history on LevelDB. This change only refactors the existing code and tests. It does not add new functionality or any new tests. There will be future changes that add history support on LevelDB and clean up tests to work against LevelDB. Note: History is not enabled by default. History must be enabled in core.yaml historyDatabase for it's unit tests to run. Change-Id: Ia5293cd345be4499e5e3df0c2949af16f71a608d Signed-off-by: denyeart <[email protected]>
1 parent 77cd1dc commit 74eeb66

9 files changed

+187
-106
lines changed

core/ledger/history/couchdb_histmgr.go core/ledger/kvledger/history/histmgr/couchdbhistmgr/couchdb_histmgr.go

+10-44
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,14 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package history
17+
package couchdbhistmgr
1818

1919
import (
20-
"bytes"
2120
"encoding/json"
2221
"fmt"
23-
"strconv"
2422

2523
"github.com/hyperledger/fabric/core/ledger"
24+
helper "github.com/hyperledger/fabric/core/ledger/kvledger/history/histmgr"
2625
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwset"
2726
"github.com/hyperledger/fabric/core/ledger/util/couchdb"
2827
"github.com/hyperledger/fabric/protos/common"
@@ -39,11 +38,9 @@ type couchSavepointData struct {
3938
UpdateSeq string `json:"UpdateSeq"`
4039
}
4140

42-
var logger = logging.MustGetLogger("history")
41+
var logger = logging.MustGetLogger("couchdbhistmgr")
4342

44-
var compositeKeySep = []byte{0x00}
45-
46-
// CouchDBHistMgr a simple implementation of interface `histmgmt.HistMgr'.
43+
// CouchDBHistMgr a simple implementation of interface `histmgr.HistMgr'.
4744
// TODO This implementation does not currently use a lock but may need one to ensure query's are consistent
4845
type CouchDBHistMgr struct {
4946
couchDB *couchdb.CouchDatabase // COUCHDB new properties for CouchDB
@@ -64,12 +61,12 @@ func NewCouchDBHistMgr(couchDBConnectURL string, dbName string, id string, pw st
6461
return &CouchDBHistMgr{couchDB: couchDB}
6562
}
6663

67-
// NewHistoryQueryExecutor implements method in interface `histmgmt.HistMgr'.
64+
// NewHistoryQueryExecutor implements method in interface `histr.HistMgr'.
6865
func (histmgr *CouchDBHistMgr) NewHistoryQueryExecutor() (ledger.HistoryQueryExecutor, error) {
6966
return &CouchDBHistQueryExecutor{histmgr}, nil
7067
}
7168

72-
// Commit implements method in interface `histmgmt.HistMgr`
69+
// Commit implements method in interface `histmgr.HistMgr`
7370
// This writes to a separate history database.
7471
// TODO dpending on how invalid transactions are handled may need to filter what history commits.
7572
func (histmgr *CouchDBHistMgr) Commit(block *common.Block) error {
@@ -113,7 +110,7 @@ func (histmgr *CouchDBHistMgr) Commit(block *common.Block) error {
113110
for _, kvWrite := range nsRWSet.Writes {
114111
writeKey := kvWrite.Key
115112
writeValue := kvWrite.Value
116-
compositeKey := constructCompositeKey(ns, writeKey, blockNo, tranNo)
113+
compositeKey := helper.ConstructCompositeKey(ns, writeKey, blockNo, tranNo)
117114
var bytesDoc []byte
118115

119116
logger.Debugf("===HISTORYDB=== ns (namespace or cc id) = %v, writeKey: %v, compositeKey: %v, writeValue = %v",
@@ -195,8 +192,8 @@ func (histmgr *CouchDBHistMgr) getTransactionsForNsKey(namespace string, key str
195192
var compositeStartKey []byte
196193
var compositeEndKey []byte
197194
if key != "" {
198-
compositeStartKey = constructPartialCompositeKey(namespace, key, false)
199-
compositeEndKey = constructPartialCompositeKey(namespace, key, true)
195+
compositeStartKey = helper.ConstructPartialCompositeKey(namespace, key, false)
196+
compositeEndKey = helper.ConstructPartialCompositeKey(namespace, key, true)
200197
}
201198

202199
//TODO the limit should not be hardcoded. Need the config.
@@ -227,37 +224,6 @@ func (txmgr *CouchDBHistMgr) GetBlockNumFromSavepoint() (uint64, error) {
227224
return savepointDoc.BlockNum, nil
228225
}
229226

230-
func constructCompositeKey(ns string, key string, blocknum uint64, trannum uint64) string {
231-
//History Key is: "namespace key blocknum trannum"", with namespace being the chaincode id
232-
233-
// TODO - We will likely want sortable varint encoding, rather then a simple number, in order to support sorted key scans
234-
var buffer bytes.Buffer
235-
buffer.WriteString(ns)
236-
buffer.WriteByte(0)
237-
buffer.WriteString(key)
238-
buffer.WriteByte(0)
239-
buffer.WriteString(strconv.Itoa(int(blocknum)))
240-
buffer.WriteByte(0)
241-
buffer.WriteString(strconv.Itoa(int(trannum)))
242-
243-
return buffer.String()
244-
}
245-
246-
func constructPartialCompositeKey(ns string, key string, endkey bool) []byte {
247-
compositeKey := []byte(ns)
248-
compositeKey = append(compositeKey, compositeKeySep...)
249-
compositeKey = append(compositeKey, []byte(key)...)
250-
if endkey {
251-
compositeKey = append(compositeKey, []byte("1")...)
252-
}
253-
return compositeKey
254-
}
255-
256-
func splitCompositeKey(compositePartialKey []byte, compositeKey []byte) (string, string) {
257-
split := bytes.SplitN(compositeKey, compositePartialKey, 2)
258-
return string(split[0]), string(split[1])
259-
}
260-
261227
type histScanner struct {
262228
cursor int
263229
compositePartialKey []byte
@@ -283,7 +249,7 @@ func (scanner *histScanner) next() (*historicValue, error) {
283249

284250
selectedValue := scanner.results[scanner.cursor]
285251

286-
_, blockNumTranNum := splitCompositeKey(scanner.compositePartialKey, []byte(selectedValue.ID))
252+
_, blockNumTranNum := helper.SplitCompositeKey(scanner.compositePartialKey, []byte(selectedValue.ID))
287253

288254
return &historicValue{blockNumTranNum, selectedValue.Value}, nil
289255

core/ledger/history/couchdb_histmgr_test.go core/ledger/kvledger/history/histmgr/couchdbhistmgr/couchdb_histmgr_test.go

+39-31
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package history
17+
package couchdbhistmgr
1818

1919
import (
2020
"fmt"
2121
"testing"
2222

23+
helper "github.com/hyperledger/fabric/core/ledger/kvledger/history/histmgr"
2324
"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
2425
"github.com/hyperledger/fabric/core/ledger/testutil"
2526
)
@@ -34,48 +35,48 @@ otherwise HistoryDB may not be installed and all the tests would fail
3435
func TestHistoryDatabaseAutoCreate(t *testing.T) {
3536

3637
//call a helper method to load the core.yaml
37-
testutil.SetupCoreYAMLConfig("./../../../peer")
38+
testutil.SetupCoreYAMLConfig("./../../../../../../peer")
3839
logger.Debugf("===HISTORYDB=== TestHistoryDatabaseAutoCreate IsCouchDBEnabled()value: %v , IsHistoryDBEnabled()value: %v\n",
3940
ledgerconfig.IsCouchDBEnabled(), ledgerconfig.IsHistoryDBEnabled())
4041

4142
if ledgerconfig.IsHistoryDBEnabled() == true {
4243

43-
env := newTestEnvHistoryCouchDB(t, "history-test")
44-
env.cleanup() //cleanup at the beginning to ensure the database doesn't exist already
45-
defer env.cleanup() //and cleanup at the end
44+
env := newTestEnvCouchDB(t, "history-test")
45+
env.cleanupCouchDB() //cleanup at the beginning to ensure the database doesn't exist already
46+
defer env.cleanupCouchDB() //and cleanup at the end
4647

47-
logger.Debugf("===HISTORYDB=== env.couchDBAddress: %v , env.couchDatabaseName: %v env.couchUsername: %v env.couchPassword: %v\n",
48-
env.couchDBAddress, env.couchDatabaseName, env.couchUsername, env.couchPassword)
48+
logger.Debugf("===HISTORYDB=== env.CouchDBAddress: %v , env.CouchDatabaseName: %v env.CouchUsername: %v env.CouchPassword: %v\n",
49+
env.CouchDBAddress, env.CouchDatabaseName, env.CouchUsername, env.CouchPassword)
4950

5051
histMgr := NewCouchDBHistMgr(
51-
env.couchDBAddress, //couchDB Address
52-
env.couchDatabaseName, //couchDB db name
53-
env.couchUsername, //enter couchDB id
54-
env.couchPassword) //enter couchDB pw
52+
env.CouchDBAddress, //couchDB Address
53+
env.CouchDatabaseName, //couchDB db name
54+
env.CouchUsername, //enter couchDB id
55+
env.CouchPassword) //enter couchDB pw
5556

5657
//NewCouchDBhistMgr should have automatically created the database, let's make sure it has been created
5758
//Retrieve the info for the new database and make sure the name matches
5859
dbResp, _, errdb := histMgr.couchDB.GetDatabaseInfo()
5960
testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information"))
60-
testutil.AssertEquals(t, dbResp.DbName, env.couchDatabaseName)
61+
testutil.AssertEquals(t, dbResp.DbName, env.CouchDatabaseName)
6162

6263
//Call NewCouchDBhistMgr again, this time the database will already exist from last time
6364
histMgr2 := NewCouchDBHistMgr(
64-
env.couchDBAddress, //couchDB Address
65-
env.couchDatabaseName, //couchDB db name
66-
env.couchUsername, //enter couchDB id
67-
env.couchPassword) //enter couchDB pw
65+
env.CouchDBAddress, //couchDB Address
66+
env.CouchDatabaseName, //couchDB db name
67+
env.CouchUsername, //enter couchDB id
68+
env.CouchPassword) //enter couchDB pw
6869

6970
//Retrieve the info for the database again, and make sure the name still matches
7071
dbResp2, _, errdb2 := histMgr2.couchDB.GetDatabaseInfo()
7172
testutil.AssertNoError(t, errdb2, fmt.Sprintf("Error when trying to retrieve database information"))
72-
testutil.AssertEquals(t, dbResp2.DbName, env.couchDatabaseName)
73+
testutil.AssertEquals(t, dbResp2.DbName, env.CouchDatabaseName)
7374

7475
}
7576
}
7677

7778
func TestConstructCompositeKey(t *testing.T) {
78-
compositeKey := constructCompositeKey("ns1", "key1", 1, 1)
79+
compositeKey := helper.ConstructCompositeKey("ns1", "key1", 1, 1)
7980

8081
var compositeKeySep = []byte{0x00}
8182
var strKeySep = string(compositeKeySep)
@@ -86,24 +87,29 @@ func TestConstructCompositeKey(t *testing.T) {
8687
//TestSavepoint tests the recordSavepoint and GetBlockNumfromSavepoint methods for recording and reading a savepoint document
8788
func TestSavepoint(t *testing.T) {
8889

90+
//call a helper method to load the core.yaml
91+
testutil.SetupCoreYAMLConfig("./../../../../../../peer")
92+
logger.Debugf("===HISTORYDB=== TestHistoryDatabaseAutoCreate IsCouchDBEnabled()value: %v , IsHistoryDBEnabled()value: %v\n",
93+
ledgerconfig.IsCouchDBEnabled(), ledgerconfig.IsHistoryDBEnabled())
94+
8995
if ledgerconfig.IsHistoryDBEnabled() == true {
9096

91-
env := newTestEnvHistoryCouchDB(t, "history-test")
92-
env.cleanup() //cleanup at the beginning to ensure the database doesn't exist already
93-
defer env.cleanup() //and cleanup at the end
97+
env := newTestEnvCouchDB(t, "history-test")
98+
env.cleanupCouchDB() //cleanup at the beginning to ensure the database doesn't exist already
99+
defer env.cleanupCouchDB() //and cleanup at the end
94100

95101
logger.Debugf("===HISTORYDB=== env.couchDBAddress: %v , env.couchDatabaseName: %v env.couchUsername: %v env.couchPassword: %v\n",
96-
env.couchDBAddress, env.couchDatabaseName, env.couchUsername, env.couchPassword)
102+
env.CouchDBAddress, env.CouchDatabaseName, env.CouchUsername, env.CouchPassword)
97103

98104
histMgr := NewCouchDBHistMgr(
99-
env.couchDBAddress, //couchDB Address
100-
env.couchDatabaseName, //couchDB db name
101-
env.couchUsername, //enter couchDB id
102-
env.couchPassword) //enter couchDB pw
105+
env.CouchDBAddress, //couchDB Address
106+
env.CouchDatabaseName, //couchDB db name
107+
env.CouchUsername, //enter couchDB id
108+
env.CouchPassword) //enter couchDB pw
103109

104110
// read the savepoint
105111
blockNum, err := histMgr.GetBlockNumFromSavepoint()
106-
testutil.AssertEquals(t, blockNum, 0)
112+
testutil.AssertEquals(t, blockNum, uint64(0))
107113

108114
// record savepoint
109115
blockNo := uint64(5)
@@ -117,16 +123,18 @@ func TestSavepoint(t *testing.T) {
117123
}
118124
}
119125

126+
/*
120127
//History Database commit and read is being tested with kv_ledger_test.go.
121128
//This test will push some of the testing down into history itself
122129
func TestHistoryDatabaseCommit(t *testing.T) {
123-
//call a helper method to load the core.yaml
124-
testutil.SetupCoreYAMLConfig("./../../../peer")
125-
logger.Debugf("===HISTORYDB=== TestHistoryDatabaseCommit IsCouchDBEnabled()value: %v , IsHistoryDBEnabled()value: %v\n",
130+
131+
testutil.SetupCoreYAMLConfig("./../../../../../../peer")
132+
logger.Debugf("===HISTORYDB=== TestHistoryDatabaseAutoCreate IsCouchDBEnabled()value: %v , IsHistoryDBEnabled()value: %v\n",
126133
ledgerconfig.IsCouchDBEnabled(), ledgerconfig.IsHistoryDBEnabled())
127134
128135
if ledgerconfig.IsHistoryDBEnabled() == true {
129-
//TODO Build the necessary infrastructure so that history can be tested iwthout ledger
136+
//TODO Build the necessary infrastructure so that history can be tested without ledger
130137
131138
}
132139
}
140+
*/

core/ledger/history/couchdb_history_query_executer.go core/ledger/kvledger/history/histmgr/couchdbhistmgr/couchdb_history_query_executer.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package history
17+
package couchdbhistmgr
1818

1919
import "github.com/hyperledger/fabric/core/ledger"
2020

@@ -47,6 +47,7 @@ func (itr *qHistoryItr) Next() (ledger.QueryResult, error) {
4747
return nil, nil
4848
}
4949
//TODO Returning blockNumTrannum as TxID for now but eventually will return txID instead
50+
//TODO This includes the seperator before the blocknum and tran num: aka(see test): strKeySep+"1"+strKeySep+"1"
5051
return &ledger.KeyModification{TxID: historicValue.blockNumTranNum, Value: historicValue.value}, nil
5152
}
5253

core/ledger/history/pkg_test.go core/ledger/kvledger/history/histmgr/couchdbhistmgr/pkg_test.go

+24-23
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package history
17+
package couchdbhistmgr
1818

1919
import (
2020
"testing"
@@ -23,33 +23,34 @@ import (
2323
"github.com/hyperledger/fabric/core/ledger/util/couchdb"
2424
)
2525

26-
//Complex setup to test the use of couch in ledger
27-
type testEnvHistoryCouchDB struct {
28-
couchDBAddress string
29-
couchDatabaseName string
30-
couchUsername string
31-
couchPassword string
26+
//TestEnvCouchDB Complex setup to test the use of couchDB in ledger
27+
type testEnvCouchDB struct {
28+
CouchDBAddress string
29+
CouchDatabaseName string
30+
CouchUsername string
31+
CouchPassword string
3232
}
3333

34-
func newTestEnvHistoryCouchDB(t testing.TB, dbName string) *testEnvHistoryCouchDB {
35-
36-
couchDBDef := ledgerconfig.GetCouchDBDefinition()
37-
38-
return &testEnvHistoryCouchDB{
39-
couchDBAddress: couchDBDef.URL,
40-
couchDatabaseName: dbName,
41-
couchUsername: couchDBDef.Username,
42-
couchPassword: couchDBDef.Password,
43-
}
44-
}
45-
46-
func (env *testEnvHistoryCouchDB) cleanup() {
47-
34+
//CleanupCouchDB to clean up the test of couchDB in ledger
35+
func (env *testEnvCouchDB) cleanupCouchDB() {
4836
//create a new connection
49-
couchInstance, err := couchdb.CreateCouchInstance(env.couchDBAddress, env.couchUsername, env.couchPassword)
50-
couchDB, err := couchdb.CreateCouchDatabase(*couchInstance, env.couchDatabaseName)
37+
couchInstance, err := couchdb.CreateCouchInstance(env.CouchDBAddress, env.CouchUsername, env.CouchPassword)
38+
couchDB, err := couchdb.CreateCouchDatabase(*couchInstance, env.CouchDatabaseName)
5139
if err == nil {
5240
//drop the test database if it already existed
5341
couchDB.DropDatabase()
5442
}
5543
}
44+
45+
//NewTestEnvCouchDB to clean up the test of couchDB in ledger
46+
func newTestEnvCouchDB(t testing.TB, dbName string) *testEnvCouchDB {
47+
48+
couchDBDef := ledgerconfig.GetCouchDBDefinition()
49+
50+
return &testEnvCouchDB{
51+
CouchDBAddress: couchDBDef.URL,
52+
CouchDatabaseName: dbName,
53+
CouchUsername: couchDBDef.Username,
54+
CouchPassword: couchDBDef.Password,
55+
}
56+
}

core/ledger/history/histmgmt.go core/ledger/kvledger/history/histmgr/histmgr.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package history
17+
package histmgr
1818

1919
import "github.com/hyperledger/fabric/protos/common"
2020
import "github.com/hyperledger/fabric/core/ledger"

0 commit comments

Comments
 (0)