github.com/renegr87/renegr87@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/statedb/statecouchdb/metadata_retrieval.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package statecouchdb
     8  
     9  import (
    10  	"fmt"
    11  
    12  	"github.com/hyperledger/fabric/core/ledger/util/couchdb"
    13  )
    14  
    15  // nsMetadataRetriever implements `batch` interface and wraps the function `retrieveNsMetadata`
    16  // for allowing parallel execution of this function for different namespaces
    17  type nsMetadataRetriever struct {
    18  	ns              string
    19  	db              *couchdb.CouchDatabase
    20  	keys            []string
    21  	executionResult []*couchdb.DocMetadata
    22  }
    23  
    24  // subNsMetadataRetriever implements `batch` interface and wraps the function
    25  // `couchdb.BatchRetrieveDocumentMetadata` for allowing parallel execution of
    26  // this function for different sets of keys within a namespace. Different sets
    27  // of keys are expected to be created based on the batch update size configured
    28  // for the database.
    29  
    30  type subNsMetadataRetriever nsMetadataRetriever
    31  
    32  // retrievedMetadata retrieves the metadata for a collection of `namespace-keys` combination
    33  func (vdb *VersionedDB) retrieveMetadata(nsKeysMap map[string][]string) (map[string][]*couchdb.DocMetadata, error) {
    34  	// construct one batch per namespace
    35  	nsMetadataRetrievers := []batch{}
    36  	for ns, keys := range nsKeysMap {
    37  		db, err := vdb.getNamespaceDBHandle(ns)
    38  		if err != nil {
    39  			return nil, err
    40  		}
    41  		nsMetadataRetrievers = append(nsMetadataRetrievers, &nsMetadataRetriever{ns: ns, db: db, keys: keys})
    42  	}
    43  	if err := executeBatches(nsMetadataRetrievers); err != nil {
    44  		return nil, err
    45  	}
    46  	// accumulate results from each batch
    47  	executionResults := make(map[string][]*couchdb.DocMetadata)
    48  	for _, r := range nsMetadataRetrievers {
    49  		nsMetadataRetriever := r.(*nsMetadataRetriever)
    50  		executionResults[nsMetadataRetriever.ns] = nsMetadataRetriever.executionResult
    51  	}
    52  	return executionResults, nil
    53  }
    54  
    55  // retrieveNsMetadata retrieves metadata for a given namespace
    56  func retrieveNsMetadata(db *couchdb.CouchDatabase, keys []string) ([]*couchdb.DocMetadata, error) {
    57  	// construct one batch per group of keys based on maxBatchSize
    58  	maxBatchSize := db.CouchInstance.MaxBatchUpdateSize()
    59  	batches := []batch{}
    60  	remainingKeys := keys
    61  	for {
    62  		numKeys := minimum(maxBatchSize, len(remainingKeys))
    63  		if numKeys == 0 {
    64  			break
    65  		}
    66  		batch := &subNsMetadataRetriever{db: db, keys: remainingKeys[:numKeys]}
    67  		batches = append(batches, batch)
    68  		remainingKeys = remainingKeys[numKeys:]
    69  	}
    70  	if err := executeBatches(batches); err != nil {
    71  		return nil, err
    72  	}
    73  	// accumulate results from each batch
    74  	var executionResults []*couchdb.DocMetadata
    75  	for _, b := range batches {
    76  		executionResults = append(executionResults, b.(*subNsMetadataRetriever).executionResult...)
    77  	}
    78  	return executionResults, nil
    79  }
    80  
    81  func (r *nsMetadataRetriever) execute() error {
    82  	var err error
    83  	if r.executionResult, err = retrieveNsMetadata(r.db, r.keys); err != nil {
    84  		return err
    85  	}
    86  	return nil
    87  }
    88  
    89  func (r *nsMetadataRetriever) String() string {
    90  	return fmt.Sprintf("nsMetadataRetriever:ns=%s, num keys=%d", r.ns, len(r.keys))
    91  }
    92  
    93  func (b *subNsMetadataRetriever) execute() error {
    94  	var err error
    95  	if b.executionResult, err = b.db.BatchRetrieveDocumentMetadata(b.keys); err != nil {
    96  		return err
    97  	}
    98  	return nil
    99  }
   100  
   101  func (b *subNsMetadataRetriever) String() string {
   102  	return fmt.Sprintf("subNsMetadataRetriever:ns=%s, num keys=%d", b.ns, len(b.keys))
   103  }
   104  
   105  func minimum(a, b int) int {
   106  	if a < b {
   107  		return a
   108  	}
   109  	return b
   110  }