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