github.com/lzy4123/fabric@v2.1.1+incompatible/core/chaincode/lifecycle/metadata_manager.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package lifecycle 8 9 import ( 10 "sync" 11 12 "github.com/hyperledger/fabric/common/chaincode" 13 ) 14 15 // MetadataUpdateListener runs whenever there is a change to 16 // the metadata of a chaincode in the context of a specific 17 // channel. 18 type MetadataUpdateListener interface { 19 HandleMetadataUpdate(channel string, metadata chaincode.MetadataSet) 20 } 21 22 // HandleMetadataUpdateFunc is triggered upon a change in the 23 // chaincode lifecycle. 24 type HandleMetadataUpdateFunc func(channel string, metadata chaincode.MetadataSet) 25 26 // HandleMetadataUpdate runs whenever there is a change to 27 // the metadata of a chaincode in the context of a specific 28 // channel. 29 func (handleMetadataUpdate HandleMetadataUpdateFunc) HandleMetadataUpdate(channel string, metadata chaincode.MetadataSet) { 30 handleMetadataUpdate(channel, metadata) 31 } 32 33 // MetadataManager stores metadata about the chaincodes 34 // installed/deployed via _lifecycle (Metadaset) and 35 // lscc (LegacyMetadataSet) and updates any registered 36 // listeners upon a change in the metadata. 37 type MetadataManager struct { 38 mutex sync.Mutex 39 listeners []MetadataUpdateListener 40 LegacyMetadataSet map[string]chaincode.MetadataSet 41 MetadataSet map[string]chaincode.MetadataSet 42 } 43 44 func NewMetadataManager() *MetadataManager { 45 return &MetadataManager{ 46 LegacyMetadataSet: map[string]chaincode.MetadataSet{}, 47 MetadataSet: map[string]chaincode.MetadataSet{}, 48 } 49 } 50 51 // HandleMetadataUpdate implements the function of the same 52 // name in the cclifecycle.LifecycleChangeListener interface. 53 // This function is called by the legacy lifecycle (lscc) to 54 // deliver updates so we aggregate them and propagate them to 55 // our listeners. This function is also called to initialise 56 // data structures right at peer startup time. 57 func (m *MetadataManager) HandleMetadataUpdate(channel string, metadata chaincode.MetadataSet) { 58 m.mutex.Lock() 59 defer m.mutex.Unlock() 60 61 m.LegacyMetadataSet[channel] = metadata 62 m.fireListenersForChannel(channel) 63 } 64 65 // UpdateMetadata implements the function of the same name in 66 // the lifecycle.MetadataManager interface. This function is 67 // called by _lifecycle to deliver updates so we aggregate them 68 // and propagate them to our listeners. 69 func (m *MetadataManager) UpdateMetadata(channel string, metadata chaincode.MetadataSet) { 70 m.mutex.Lock() 71 defer m.mutex.Unlock() 72 73 m.MetadataSet[channel] = metadata 74 m.fireListenersForChannel(channel) 75 } 76 77 // InitializeMetadata implements the function of the 78 // same name in the lifecycle.MetadataManager interface. 79 // This function is called by _lifecycle to initialize 80 // metadata for the given channel. 81 func (m *MetadataManager) InitializeMetadata(channel string, metadata chaincode.MetadataSet) { 82 m.mutex.Lock() 83 defer m.mutex.Unlock() 84 85 m.MetadataSet[channel] = metadata 86 } 87 88 // AddListener registers the given listener to be triggered upon 89 // a lifecycle change 90 func (m *MetadataManager) AddListener(listener MetadataUpdateListener) { 91 m.mutex.Lock() 92 defer m.mutex.Unlock() 93 m.listeners = append(m.listeners, listener) 94 } 95 96 // NOTE: caller must hold the mutex 97 func (m *MetadataManager) fireListenersForChannel(channel string) { 98 aggregatedMD := chaincode.MetadataSet{} 99 mdMapNewLifecycle := map[string]struct{}{} 100 101 for _, meta := range m.MetadataSet[channel] { 102 mdMapNewLifecycle[meta.Name] = struct{}{} 103 104 // in mdMapNewLifecycle we keep track of all 105 // metadata from the new lifecycle so that 106 // we can appropriately shadow any definition 107 // in the old lifecycle. However we return 108 // metadata to our caller only for chaincodes 109 // that are approved and locally installed, 110 // which is why we put metadata in the 111 // aggregatedMD slice only if it is approved 112 // and installed. 113 if meta.Installed && meta.Approved { 114 aggregatedMD = append(aggregatedMD, meta) 115 } 116 } 117 118 for _, meta := range m.LegacyMetadataSet[channel] { 119 if _, in := mdMapNewLifecycle[meta.Name]; in { 120 continue 121 } 122 123 aggregatedMD = append(aggregatedMD, meta) 124 } 125 126 for _, listener := range m.listeners { 127 listener.HandleMetadataUpdate(channel, aggregatedMD) 128 } 129 }