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