github.com/kaituanwang/hyperledger@v2.0.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  }