github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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 // VersionedQueryRecord encloses a query record 79 type VersionedQueryRecord struct { 80 Namespace string 81 Key string 82 Version *version.Height 83 Record []byte 84 } 85 86 // ResultsIterator hepls in iterates over query results 87 type ResultsIterator interface { 88 Next() (QueryResult, error) 89 Close() 90 } 91 92 // QueryResult - a general interface for supporting different types of query results. Actual types differ for different queries 93 type QueryResult interface{} 94 95 type nsUpdates struct { 96 m map[string]*VersionedValue 97 } 98 99 func newNsUpdates() *nsUpdates { 100 return &nsUpdates{make(map[string]*VersionedValue)} 101 } 102 103 // UpdateBatch encloses the details of multiple `updates` 104 type UpdateBatch struct { 105 updates map[string]*nsUpdates 106 } 107 108 // NewUpdateBatch constructs an instance of a Batch 109 func NewUpdateBatch() *UpdateBatch { 110 return &UpdateBatch{make(map[string]*nsUpdates)} 111 } 112 113 // Get returns the VersionedValue for the given namespace and key 114 func (batch *UpdateBatch) Get(ns string, key string) *VersionedValue { 115 nsUpdates, ok := batch.updates[ns] 116 if !ok { 117 return nil 118 } 119 vv, ok := nsUpdates.m[key] 120 if !ok { 121 return nil 122 } 123 return vv 124 } 125 126 // Put adds a VersionedKV 127 func (batch *UpdateBatch) Put(ns string, key string, value []byte, version *version.Height) { 128 if value == nil { 129 panic("Nil value not allowed") 130 } 131 nsUpdates := batch.getOrCreateNsUpdates(ns) 132 nsUpdates.m[key] = &VersionedValue{value, version} 133 } 134 135 // Delete deletes a Key and associated value 136 func (batch *UpdateBatch) Delete(ns string, key string, version *version.Height) { 137 nsUpdates := batch.getOrCreateNsUpdates(ns) 138 nsUpdates.m[key] = &VersionedValue{nil, version} 139 } 140 141 // Exists checks whether the given key exists in the batch 142 func (batch *UpdateBatch) Exists(ns string, key string) bool { 143 nsUpdates, ok := batch.updates[ns] 144 if !ok { 145 return false 146 } 147 _, ok = nsUpdates.m[key] 148 return ok 149 } 150 151 // GetUpdatedNamespaces returns the names of the namespaces that are updated 152 func (batch *UpdateBatch) GetUpdatedNamespaces() []string { 153 namespaces := make([]string, len(batch.updates)) 154 i := 0 155 for ns := range batch.updates { 156 namespaces[i] = ns 157 i++ 158 } 159 return namespaces 160 } 161 162 // GetUpdates returns all the updates for a namespace 163 func (batch *UpdateBatch) GetUpdates(ns string) map[string]*VersionedValue { 164 nsUpdates, ok := batch.updates[ns] 165 if !ok { 166 return nil 167 } 168 return nsUpdates.m 169 } 170 171 // GetRangeScanIterator returns an iterator that iterates over keys of a specific namespace in sorted order 172 // In other word this gives the same functionality over the contents in the `UpdateBatch` as 173 // `VersionedDB.GetStateRangeScanIterator()` method gives over the contents in the statedb 174 // This function can be used for querying the contents in the updateBatch before they are committed to the statedb. 175 // For instance, a validator implementation can used this to verify the validity of a range query of a transaction 176 // where the UpdateBatch represents the union of the modifications performed by the preceding valid transactions in the same block 177 // (Assuming Group commit approach where we commit all the updates caused by a block together). 178 func (batch *UpdateBatch) GetRangeScanIterator(ns string, startKey string, endKey string) ResultsIterator { 179 return newNsIterator(ns, startKey, endKey, batch) 180 } 181 182 func (batch *UpdateBatch) getOrCreateNsUpdates(ns string) *nsUpdates { 183 nsUpdates := batch.updates[ns] 184 if nsUpdates == nil { 185 nsUpdates = newNsUpdates() 186 batch.updates[ns] = nsUpdates 187 } 188 return nsUpdates 189 } 190 191 type nsIterator struct { 192 ns string 193 nsUpdates *nsUpdates 194 sortedKeys []string 195 nextIndex int 196 lastIndex int 197 } 198 199 func newNsIterator(ns string, startKey string, endKey string, batch *UpdateBatch) *nsIterator { 200 nsUpdates, ok := batch.updates[ns] 201 if !ok { 202 return &nsIterator{} 203 } 204 sortedKeys := util.GetSortedKeys(nsUpdates.m) 205 var nextIndex int 206 var lastIndex int 207 if startKey == "" { 208 nextIndex = 0 209 } else { 210 nextIndex = sort.SearchStrings(sortedKeys, startKey) 211 } 212 if endKey == "" { 213 lastIndex = len(sortedKeys) 214 } else { 215 lastIndex = sort.SearchStrings(sortedKeys, endKey) 216 } 217 return &nsIterator{ns, nsUpdates, sortedKeys, nextIndex, lastIndex} 218 } 219 220 // Next gives next key and versioned value. It returns a nil when exhausted 221 func (itr *nsIterator) Next() (QueryResult, error) { 222 if itr.nextIndex >= itr.lastIndex { 223 return nil, nil 224 } 225 key := itr.sortedKeys[itr.nextIndex] 226 vv := itr.nsUpdates.m[key] 227 itr.nextIndex++ 228 return &VersionedKV{CompositeKey{itr.ns, key}, VersionedValue{vv.Value, vv.Version}}, nil 229 } 230 231 // Close implements the method from QueryResult interface 232 func (itr *nsIterator) Close() { 233 // do nothing 234 }