github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/ledger/kvledger/txmgmt/statedb/statedb.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 statedb 18 19 import ( 20 "sort" 21 22 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version" 23 "github.com/hyperledger/fabric/core/ledger/util" 24 ) 25 26 // VersionedDBProvider provides an instance of an versioned DB 27 type VersionedDBProvider interface { 28 // GetDBHandle returns a handle to a VersionedDB 29 GetDBHandle(id string) (VersionedDB, error) 30 // Close closes all the VersionedDB instances and releases any resources held by VersionedDBProvider 31 Close() 32 } 33 34 // VersionedDB lists methods that a db is supposed to implement 35 type VersionedDB interface { 36 // GetState gets the value for given namespace and key. For a chaincode, the namespace corresponds to the chaincodeId 37 GetState(namespace string, key string) (*VersionedValue, error) 38 // GetStateMultipleKeys gets the values for multiple keys in a single call 39 GetStateMultipleKeys(namespace string, keys []string) ([]*VersionedValue, error) 40 // GetStateRangeScanIterator returns an iterator that contains all the key-values between given key ranges. 41 // startKey is inclusive 42 // endKey is exclusive 43 // The returned ResultsIterator contains results of type *VersionedKV 44 GetStateRangeScanIterator(namespace string, startKey string, endKey string) (ResultsIterator, error) 45 // ExecuteQuery executes the given query and returns an iterator that contains results of type *VersionedKV. 46 ExecuteQuery(namespace, query string) (ResultsIterator, error) 47 // ApplyUpdates applies the batch to the underlying db. 48 // height is the height of the highest transaction in the Batch that 49 // a state db implementation is expected to ues as a save point 50 ApplyUpdates(batch *UpdateBatch, height *version.Height) error 51 // GetLatestSavePoint returns the height of the highest transaction upto which 52 // the state db is consistent 53 GetLatestSavePoint() (*version.Height, error) 54 // Open opens the db 55 Open() error 56 // Close closes the db 57 Close() 58 } 59 60 // CompositeKey encloses Namespace and Key components 61 type CompositeKey struct { 62 Namespace string 63 Key string 64 } 65 66 // VersionedValue encloses value and corresponding version 67 type VersionedValue struct { 68 Value []byte 69 Version *version.Height 70 } 71 72 // VersionedKV encloses key and corresponding VersionedValue 73 type VersionedKV struct { 74 CompositeKey 75 VersionedValue 76 } 77 78 // ResultsIterator hepls in iterates over query results 79 type ResultsIterator interface { 80 Next() (QueryResult, error) 81 Close() 82 } 83 84 // QueryResult - a general interface for supporting different types of query results. Actual types differ for different queries 85 type QueryResult interface{} 86 87 type nsUpdates struct { 88 m map[string]*VersionedValue 89 } 90 91 func newNsUpdates() *nsUpdates { 92 return &nsUpdates{make(map[string]*VersionedValue)} 93 } 94 95 // UpdateBatch encloses the details of multiple `updates` 96 type UpdateBatch struct { 97 updates map[string]*nsUpdates 98 } 99 100 // NewUpdateBatch constructs an instance of a Batch 101 func NewUpdateBatch() *UpdateBatch { 102 return &UpdateBatch{make(map[string]*nsUpdates)} 103 } 104 105 // Get returns the VersionedValue for the given namespace and key 106 func (batch *UpdateBatch) Get(ns string, key string) *VersionedValue { 107 nsUpdates, ok := batch.updates[ns] 108 if !ok { 109 return nil 110 } 111 vv, ok := nsUpdates.m[key] 112 if !ok { 113 return nil 114 } 115 return vv 116 } 117 118 // Put adds a VersionedKV 119 func (batch *UpdateBatch) Put(ns string, key string, value []byte, version *version.Height) { 120 if value == nil { 121 panic("Nil value not allowed") 122 } 123 nsUpdates := batch.getOrCreateNsUpdates(ns) 124 nsUpdates.m[key] = &VersionedValue{value, version} 125 } 126 127 // Delete deletes a Key and associated value 128 func (batch *UpdateBatch) Delete(ns string, key string, version *version.Height) { 129 nsUpdates := batch.getOrCreateNsUpdates(ns) 130 nsUpdates.m[key] = &VersionedValue{nil, version} 131 } 132 133 // Exists checks whether the given key exists in the batch 134 func (batch *UpdateBatch) Exists(ns string, key string) bool { 135 nsUpdates, ok := batch.updates[ns] 136 if !ok { 137 return false 138 } 139 _, ok = nsUpdates.m[key] 140 return ok 141 } 142 143 // GetUpdatedNamespaces returns the names of the namespaces that are updated 144 func (batch *UpdateBatch) GetUpdatedNamespaces() []string { 145 namespaces := make([]string, len(batch.updates)) 146 i := 0 147 for ns := range batch.updates { 148 namespaces[i] = ns 149 i++ 150 } 151 return namespaces 152 } 153 154 // GetUpdates returns all the updates for a namespace 155 func (batch *UpdateBatch) GetUpdates(ns string) map[string]*VersionedValue { 156 nsUpdates, ok := batch.updates[ns] 157 if !ok { 158 return nil 159 } 160 return nsUpdates.m 161 } 162 163 // GetRangeScanIterator returns an iterator that iterates over keys of a specific namespace in sorted order 164 // In other word this gives the same functionality over the contents in the `UpdateBatch` as 165 // `VersionedDB.GetStateRangeScanIterator()` method gives over the contents in the statedb 166 // This function can be used for querying the contents in the updateBatch before they are committed to the statedb. 167 // For instance, a validator implementation can used this to verify the validity of a range query of a transaction 168 // where the UpdateBatch represents the union of the modifications performed by the preceding valid transactions in the same block 169 // (Assuming Group commit approach where we commit all the updates caused by a block together). 170 func (batch *UpdateBatch) GetRangeScanIterator(ns string, startKey string, endKey string) ResultsIterator { 171 return newNsIterator(ns, startKey, endKey, batch) 172 } 173 174 func (batch *UpdateBatch) getOrCreateNsUpdates(ns string) *nsUpdates { 175 nsUpdates := batch.updates[ns] 176 if nsUpdates == nil { 177 nsUpdates = newNsUpdates() 178 batch.updates[ns] = nsUpdates 179 } 180 return nsUpdates 181 } 182 183 type nsIterator struct { 184 ns string 185 nsUpdates *nsUpdates 186 sortedKeys []string 187 nextIndex int 188 lastIndex int 189 } 190 191 func newNsIterator(ns string, startKey string, endKey string, batch *UpdateBatch) *nsIterator { 192 nsUpdates, ok := batch.updates[ns] 193 if !ok { 194 return &nsIterator{} 195 } 196 sortedKeys := util.GetSortedKeys(nsUpdates.m) 197 var nextIndex int 198 var lastIndex int 199 if startKey == "" { 200 nextIndex = 0 201 } else { 202 nextIndex = sort.SearchStrings(sortedKeys, startKey) 203 } 204 if endKey == "" { 205 lastIndex = len(sortedKeys) 206 } else { 207 lastIndex = sort.SearchStrings(sortedKeys, endKey) 208 } 209 return &nsIterator{ns, nsUpdates, sortedKeys, nextIndex, lastIndex} 210 } 211 212 // Next gives next key and versioned value. It returns a nil when exhausted 213 func (itr *nsIterator) Next() (QueryResult, error) { 214 if itr.nextIndex >= itr.lastIndex { 215 return nil, nil 216 } 217 key := itr.sortedKeys[itr.nextIndex] 218 vv := itr.nsUpdates.m[key] 219 itr.nextIndex++ 220 return &VersionedKV{CompositeKey{itr.ns, key}, VersionedValue{vv.Value, vv.Version}}, nil 221 } 222 223 // Close implements the method from QueryResult interface 224 func (itr *nsIterator) Close() { 225 // do nothing 226 }