historyleveldb.go 5.52 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
Copyright IBM Corp. 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

		 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package historyleveldb

import (
20
	"github.com/hyperledger/fabric/common/ledger/util/leveldbhelper"
21
22
23
24
25
26
	"github.com/hyperledger/fabric/core/ledger"
	"github.com/hyperledger/fabric/core/ledger/kvledger/history/historydb"
	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwset"
	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
	"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
	"github.com/hyperledger/fabric/protos/common"
denyeart's avatar
denyeart committed
27
	putils "github.com/hyperledger/fabric/protos/utils"
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
	logging "github.com/op/go-logging"
)

var logger = logging.MustGetLogger("historyleveldb")

var compositeKeySep = []byte{0x00}
var savePointKey = []byte{0x00}
var emptyValue = []byte{}

// HistoryDBProvider implements interface HistoryDBProvider
type HistoryDBProvider struct {
	dbProvider *leveldbhelper.Provider
}

// NewHistoryDBProvider instantiates HistoryDBProvider
func NewHistoryDBProvider() *HistoryDBProvider {
	dbPath := ledgerconfig.GetHistoryLevelDBPath()
	logger.Debugf("constructing HistoryDBProvider dbPath=%s", dbPath)
	dbProvider := leveldbhelper.NewProvider(&leveldbhelper.Conf{DBPath: dbPath})
	return &HistoryDBProvider{dbProvider}
}

// GetDBHandle gets the handle to a named database
func (provider *HistoryDBProvider) GetDBHandle(dbName string) (historydb.HistoryDB, error) {
	return newHistoryDB(provider.dbProvider.GetDBHandle(dbName), dbName), nil
}

// Close closes the underlying db
func (provider *HistoryDBProvider) Close() {
	provider.dbProvider.Close()
}

// historyDB implements HistoryDB interface
type historyDB struct {
	db     *leveldbhelper.DBHandle
	dbName string
}

// newHistoryDB constructs an instance of HistoryDB
func newHistoryDB(db *leveldbhelper.DBHandle, dbName string) *historyDB {
	return &historyDB{db, dbName}
}

// Open implements method in HistoryDB interface
func (historyDB *historyDB) Open() error {
	// do nothing because shared db is used
	return nil
}

// Close implements method in HistoryDB interface
func (historyDB *historyDB) Close() {
	// do nothing because shared db is used
}

// Commit implements method in HistoryDB interface
func (historyDB *historyDB) Commit(block *common.Block) error {

	logger.Debugf("Entering HistoryLevelDB.Commit()")

	//Get the blocknumber off of the header
	blockNo := block.Header.Number
	//Set the starting tranNo to 0
	var tranNo uint64

	dbBatch := leveldbhelper.NewUpdateBatch()

	logger.Debugf("Updating history for blockNo: %v with [%d] transactions",
		blockNo, len(block.Data.Data))

	//TODO add check for invalid trans in bit array
	for _, envBytes := range block.Data.Data {
		tranNo++

denyeart's avatar
denyeart committed
101
		env, err := putils.GetEnvelopeFromBlock(envBytes)
102
103
104
105
		if err != nil {
			return err
		}

denyeart's avatar
denyeart committed
106
107
		payload, err := putils.GetPayload(env)
		if err != nil {
108
109
110
			return err
		}

denyeart's avatar
denyeart committed
111
		if common.HeaderType(payload.Header.ChainHeader.Type) == common.HeaderType_ENDORSER_TRANSACTION {
112

denyeart's avatar
denyeart committed
113
114
115
116
117
118
			logger.Debugf("Updating history for tranNo: %d", tranNo)
			// extract actions from the envelope message
			respPayload, err := putils.GetActionFromEnvelope(envBytes)
			if err != nil {
				return err
			}
119

denyeart's avatar
denyeart committed
120
121
122
123
124
125
126
127
128
129
130
131
			//preparation for extracting RWSet from transaction
			txRWSet := &rwset.TxReadWriteSet{}

			// Get the Result from the Action and then Unmarshal
			// it into a TxReadWriteSet using custom unmarshalling
			if err = txRWSet.Unmarshal(respPayload.Results); err != nil {
				return err
			}
			// for each transaction, loop through the namespaces and writesets
			// and add a history record for each write
			for _, nsRWSet := range txRWSet.NsRWs {
				ns := nsRWSet.NameSpace
132

denyeart's avatar
denyeart committed
133
134
				for _, kvWrite := range nsRWSet.Writes {
					writeKey := kvWrite.Key
135

denyeart's avatar
denyeart committed
136
137
138
139
140
141
142
143
144
					logger.Debugf("Writing history record for: ns=%s, key=%s, blockNo=%d tranNo=%d",
						ns, writeKey, blockNo, tranNo)

					//composite key for history records is in the form ns~key~blockNo~tranNo
					compositeHistoryKey := historydb.ConstructCompositeHistoryKey(ns, writeKey, blockNo, tranNo)

					// No value is required, write an empty byte array (emptyValue) since Put() of nil is not allowed
					dbBatch.Put(compositeHistoryKey, emptyValue)
				}
145
			}
denyeart's avatar
denyeart committed
146
147
148

		} else {
			logger.Debugf("Skipping transaction %d since it is not an endorsement transaction\n", tranNo)
149
		}
denyeart's avatar
denyeart committed
150

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
	}

	// add savepoint for recovery purpose
	height := version.NewHeight(blockNo, tranNo)
	dbBatch.Put(savePointKey, height.ToBytes())

	// write the block's history records and savepoint to LevelDB
	if err := historyDB.db.WriteBatch(dbBatch, false); err != nil {
		return err
	}

	return nil
}

// NewHistoryQueryExecutor implements method in HistoryDB interface
func (historyDB *historyDB) NewHistoryQueryExecutor() (ledger.HistoryQueryExecutor, error) {
	return &LevelHistoryDBQueryExecutor{historyDB}, nil
}

// GetBlockNumFromSavepoint implements method in HistoryDB interface
func (historyDB *historyDB) GetBlockNumFromSavepoint() (uint64, error) {
	versionBytes, err := historyDB.db.Get(savePointKey)
	if err != nil || versionBytes == nil {
		return 0, err
	}
	height, _ := version.NewHeightFromBytes(versionBytes)
	return height.BlockNum, nil
}