Skip to content

Commit

Permalink
[FAB-5809] Add bundlesource to track current bndl
Browse files Browse the repository at this point in the history
Since the channelconfig bundle is immutable, but the channel config can
change, it's necessary to have an encapsulating structure which retains
a reference to the current immutable bundle.  Because the configuration
may be referenced by multiple go routines, it's important that access to
the reference be synchronized, in this case, through the sync/atomic
Load/Store operations.

This CR adds a BundleSoure which retains a reference to a Bundle.  It
implements the standard interface for channel configuration, but always
references the config through the atomic pointer.  A caller may also
request a static version of the bundle, if multiple coherent config
calls must be made (such as listing organizations, then looking up their
MSP info in the MSP manager).

Change-Id: I825ab93fd1b769248b44b85e68412513051b54f4
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Aug 30, 2017
1 parent 3c916f5 commit 76bd30d
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
File renamed without changes.
90 changes: 90 additions & 0 deletions common/channelconfig/bundlesource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package channelconfig

import (
"sync/atomic"

oldchannelconfig "github.com/hyperledger/fabric/common/config/channel"
configtxapi "github.com/hyperledger/fabric/common/configtx/api"
"github.com/hyperledger/fabric/common/policies"
"github.com/hyperledger/fabric/msp"
)

// BundleSource stores a reference to the current configuration bundle
// It also provides a method to update this bundle. The assorted methods
// largely pass through to the underlying bundle, but do so through an atomic pointer
// so that gross go-routine reads are not vulnerable to out-of-order execution memory
// type bugs.
type BundleSource struct {
bundle atomic.Value
}

// NewBundleSource creates a new BundleSource with an initial Bundle value
func NewBundleSource(bundle *Bundle) *BundleSource {
bs := &BundleSource{}
bs.bundle.Store(bundle)
return bs
}

// Update sets a new bundle as the bundle source
func (bs *BundleSource) Update(newBundle *Bundle) {
bs.bundle.Store(newBundle)
}

// StableBundle returns a pointer to a stable Bundle.
// It is stable because calls to its assorted methods will always return the same
// result, as the underlying data structures are immutable. For instance, calling
// BundleSource.Orderer() and BundleSource.MSPManager() to get first the list of orderer
// orgs, then querying the MSP for those org definitions could result in a bug because an
// update might replace the underlying Bundle in between. Therefore, for operations
// which require consistency between the Bundle calls, the caller should first retrieve
// a StableBundle, then operate on it.
func (bs *BundleSource) StableBundle() *Bundle {
return bs.bundle.Load().(*Bundle)
}

// PolicyManager returns the policy manager constructed for this config
func (bs *BundleSource) PolicyManager() policies.Manager {
return bs.StableBundle().policyManager
}

// MSPManager returns the MSP manager constructed for this config
func (bs *BundleSource) MSPManager() msp.MSPManager {
return bs.StableBundle().mspManager
}

// ChannelConfig returns the config.Channel for the chain
func (bs *BundleSource) ChannelConfig() oldchannelconfig.Channel {
return bs.StableBundle().rootConfig.Channel()
}

// OrdererConfig returns the config.Orderer for the channel
// and whether the Orderer config exists
func (bs *BundleSource) OrdererConfig() (oldchannelconfig.Orderer, bool) {
result := bs.StableBundle().rootConfig.Orderer()
return result, result != nil
}

// ConsortiumsConfig() returns the config.Consortiums for the channel
// and whether the consortiums config exists
func (bs *BundleSource) ConsortiumsConfig() (oldchannelconfig.Consortiums, bool) {
result := bs.StableBundle().rootConfig.Consortiums()
return result, result != nil
}

// ApplicationConfig returns the configtxapplication.SharedConfig for the channel
// and whether the Application config exists
func (bs *BundleSource) ApplicationConfig() (oldchannelconfig.Application, bool) {
result := bs.StableBundle().rootConfig.Application()
return result, result != nil
}

// ConfigtxManager returns the configtx.Manager for the channel
func (bs *BundleSource) ConfigtxManager() configtxapi.Manager {
return bs.StableBundle().configtxManager
}

0 comments on commit 76bd30d

Please sign in to comment.