@@ -95,6 +95,10 @@ type runningChaincodes struct {
95
95
sync.RWMutex
96
96
// chaincode environment for each chaincode
97
97
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
98
102
}
99
103
100
104
//GetChain returns the chaincode framework support object
@@ -119,14 +123,22 @@ func (chaincodeSupport *ChaincodeSupport) chaincodeHasBeenLaunched(chaincode str
119
123
return chrte , hasbeenlaunched
120
124
}
121
125
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
+
122
134
// NewChaincodeSupport creates a new ChaincodeSupport instance
123
135
func NewChaincodeSupport (getCCEndpoint func () (* pb.PeerEndpoint , error ), userrunsCC bool , ccstartuptimeout time.Duration ) * ChaincodeSupport {
124
136
ccprovider .SetChaincodesPath (config .GetPath ("peer.fileSystemPath" ) + string (filepath .Separator ) + "chaincodes" )
125
137
126
138
pnid := viper .GetString ("peer.networkId" )
127
139
pid := viper .GetString ("peer.id" )
128
140
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 }
130
142
131
143
//initialize global chain
132
144
@@ -396,7 +408,8 @@ func (chaincodeSupport *ChaincodeSupport) getArgsAndEnv(cccid *ccprovider.CCCont
396
408
return args , envs , nil
397
409
}
398
410
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
400
413
func (chaincodeSupport * ChaincodeSupport ) launchAndWaitForRegister (ctxt context.Context , cccid * ccprovider.CCContext , cds * pb.ChaincodeDeploymentSpec , cLang pb.ChaincodeSpec_Type , builder api.BuildSpecFactory ) error {
401
414
canName := cccid .GetCanonicalName ()
402
415
if canName == "" {
@@ -408,9 +421,37 @@ func (chaincodeSupport *ChaincodeSupport) launchAndWaitForRegister(ctxt context.
408
421
//multiple launch by failing
409
422
if _ , hasBeenLaunched := chaincodeSupport .chaincodeHasBeenLaunched (canName ); hasBeenLaunched {
410
423
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 )
412
425
}
413
426
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
+
414
455
chaincodeSupport .runningChaincodes .Unlock ()
415
456
416
457
//launch the chaincode
@@ -535,8 +576,8 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, cccid
535
576
if chrte , ok = chaincodeSupport .chaincodeHasBeenLaunched (canName ); ok {
536
577
if ! chrte .handler .registered {
537
578
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 )
540
581
return cID , cMsg , err
541
582
}
542
583
if chrte .handler .isRunning () {
@@ -547,6 +588,16 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, cccid
547
588
return cID , cMsg , nil
548
589
}
549
590
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
+ }
550
601
}
551
602
chaincodeSupport .runningChaincodes .Unlock ()
552
603
0 commit comments