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  }