github.com/ewagmig/fabric@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 }