@@ -95,6 +95,10 @@ type runningChaincodes struct {
9595 sync.RWMutex
9696 // chaincode environment for each chaincode
9797 chaincodeMap map [string ]* chaincodeRTEnv
98+
99+ //mark the starting of launch of a chaincode so multiple requests
100+ //do not attempt to start the chaincode at the same time
101+ launchStarted map [string ]bool
98102}
99103
100104//GetChain returns the chaincode framework support object
@@ -119,14 +123,22 @@ func (chaincodeSupport *ChaincodeSupport) chaincodeHasBeenLaunched(chaincode str
119123 return chrte , hasbeenlaunched
120124}
121125
126+ //call this under lock
127+ func (chaincodeSupport * ChaincodeSupport ) launchStarted (chaincode string ) bool {
128+ if _ , launchStarted := chaincodeSupport .runningChaincodes .launchStarted [chaincode ]; launchStarted {
129+ return true
130+ }
131+ return false
132+ }
133+
122134// NewChaincodeSupport creates a new ChaincodeSupport instance
123135func NewChaincodeSupport (getCCEndpoint func () (* pb.PeerEndpoint , error ), userrunsCC bool , ccstartuptimeout time.Duration ) * ChaincodeSupport {
124136 ccprovider .SetChaincodesPath (config .GetPath ("peer.fileSystemPath" ) + string (filepath .Separator ) + "chaincodes" )
125137
126138 pnid := viper .GetString ("peer.networkId" )
127139 pid := viper .GetString ("peer.id" )
128140
129- theChaincodeSupport = & ChaincodeSupport {runningChaincodes : & runningChaincodes {chaincodeMap : make (map [string ]* chaincodeRTEnv )}, peerNetworkID : pnid , peerID : pid }
141+ theChaincodeSupport = & ChaincodeSupport {runningChaincodes : & runningChaincodes {chaincodeMap : make (map [string ]* chaincodeRTEnv ), launchStarted : make ( map [ string ] bool ) }, peerNetworkID : pnid , peerID : pid }
130142
131143 //initialize global chain
132144
@@ -396,7 +408,8 @@ func (chaincodeSupport *ChaincodeSupport) getArgsAndEnv(cccid *ccprovider.CCCont
396408 return args , envs , nil
397409}
398410
399- // launchAndWaitForRegister will launch container if not already running. Use the targz to create the image if not found
411+ //launchAndWaitForRegister will launch container if not already running. Use
412+ //the targz to create the image if not found
400413func (chaincodeSupport * ChaincodeSupport ) launchAndWaitForRegister (ctxt context.Context , cccid * ccprovider.CCContext , cds * pb.ChaincodeDeploymentSpec , cLang pb.ChaincodeSpec_Type , builder api.BuildSpecFactory ) error {
401414 canName := cccid .GetCanonicalName ()
402415 if canName == "" {
@@ -408,9 +421,37 @@ func (chaincodeSupport *ChaincodeSupport) launchAndWaitForRegister(ctxt context.
408421 //multiple launch by failing
409422 if _ , hasBeenLaunched := chaincodeSupport .chaincodeHasBeenLaunched (canName ); hasBeenLaunched {
410423 chaincodeSupport .runningChaincodes .Unlock ()
411- return fmt .Errorf ("Error chaincode is being launched: %s" , canName )
424+ return fmt .Errorf ("Error chaincode has been launched: %s" , canName )
412425 }
413426
427+ //prohibit multiple simultaneous invokes (for example while flooding the
428+ //system with invokes as in a stress test scenario) from attempting to launch
429+ //the chaincode. The first one wins. Others receive an error.
430+ //NOTE - this transient behavior as the chaincode is being launched is nothing
431+ //new. All invokes (except the one launching the CC) will fail in any case
432+ //until the container is up and registered.
433+ if chaincodeSupport .launchStarted (canName ) {
434+ chaincodeSupport .runningChaincodes .Unlock ()
435+ return fmt .Errorf ("Error chaincode is already launching: %s" , canName )
436+ }
437+
438+ //Chaincode is not up and is not in the process of being launched. Setup flag
439+ //for launching so we can proceed to do that undisturbed by other requests on
440+ //this chaincode
441+ chaincodeLogger .Debugf ("chaincode %s is being launched" , canName )
442+ chaincodeSupport .runningChaincodes .launchStarted [canName ] = true
443+
444+ //now that chaincode launch sequence is done (whether successful or not),
445+ //unset launch flag as we get out of this function. If launch was not
446+ //successful (handler was not created), next invoke will try again.
447+ defer func () {
448+ chaincodeSupport .runningChaincodes .Lock ()
449+ defer chaincodeSupport .runningChaincodes .Unlock ()
450+
451+ delete (chaincodeSupport .runningChaincodes .launchStarted , canName )
452+ chaincodeLogger .Debugf ("chaincode %s launch seq completed" , canName )
453+ }()
454+
414455 chaincodeSupport .runningChaincodes .Unlock ()
415456
416457 //launch the chaincode
@@ -535,8 +576,8 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, cccid
535576 if chrte , ok = chaincodeSupport .chaincodeHasBeenLaunched (canName ); ok {
536577 if ! chrte .handler .registered {
537578 chaincodeSupport .runningChaincodes .Unlock ()
538- chaincodeLogger .Debugf ("premature execution - chaincode (%s) is being launched " , canName )
539- err = fmt .Errorf ("premature execution - chaincode (%s) is being launched " , canName )
579+ chaincodeLogger .Debugf ("premature execution - chaincode (%s) launched and waiting for registration " , canName )
580+ err = fmt .Errorf ("premature execution - chaincode (%s) launched and waiting for registration " , canName )
540581 return cID , cMsg , err
541582 }
542583 if chrte .handler .isRunning () {
@@ -547,6 +588,16 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, cccid
547588 return cID , cMsg , nil
548589 }
549590 chaincodeLogger .Debugf ("Container not in READY state(%s)...send init/ready" , chrte .handler .FSM .Current ())
591+ } else {
592+ //chaincode is not up... but is the launch process underway? this is
593+ //strictly not necessary as the actual launch process will catch this
594+ //(in launchAndWaitForRegister), just a bit of optimization for thundering
595+ //herds
596+ if chaincodeSupport .launchStarted (canName ) {
597+ chaincodeSupport .runningChaincodes .Unlock ()
598+ err = fmt .Errorf ("premature execution - chaincode (%s) is being launched" , canName )
599+ return cID , cMsg , err
600+ }
550601 }
551602 chaincodeSupport .runningChaincodes .Unlock ()
552603
0 commit comments