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  }