@@ -7,7 +7,6 @@ SPDX-License-Identifier: Apache-2.0
7
7
package cceventmgmt
8
8
9
9
import (
10
- "bytes"
11
10
"sync"
12
11
13
12
"github.com/hyperledger/fabric/common/flogging"
@@ -39,19 +38,15 @@ type Mgr struct {
39
38
// we use this lock for contextual use
40
39
rwlock sync.RWMutex
41
40
infoProvider ChaincodeInfoProvider
42
- ccLifecycleListeners map [string ]ChaincodeLifecycleEventListener
43
- // latestChaincodeDeploys maintains last chaincode deployed for a ledger. As stated in the above comment,
44
- // since it is not easy to synchronize across block commit and install activity, this leaves a small window
45
- // where we could miss 'deployed AND installed' state. So, we explicitly maintain the chaincodes deplyed
46
- // in the last block
47
- latestChaincodeDeploys map [string ][]* ChaincodeDefinition
41
+ ccLifecycleListeners map [string ][]ChaincodeLifecycleEventListener
42
+ callbackStatus * callbackStatus
48
43
}
49
44
50
45
func newMgr (chaincodeInfoProvider ChaincodeInfoProvider ) * Mgr {
51
46
return & Mgr {
52
- infoProvider : chaincodeInfoProvider ,
53
- ccLifecycleListeners : make (map [string ]ChaincodeLifecycleEventListener ),
54
- latestChaincodeDeploys : make ( map [ string ][] * ChaincodeDefinition )}
47
+ infoProvider : chaincodeInfoProvider ,
48
+ ccLifecycleListeners : make (map [string ][ ]ChaincodeLifecycleEventListener ),
49
+ callbackStatus : newCallbackStatus ( )}
55
50
}
56
51
57
52
// Register registers a ChaincodeLifecycleEventListener for given ledgerid
@@ -60,7 +55,7 @@ func (m *Mgr) Register(ledgerid string, l ChaincodeLifecycleEventListener) {
60
55
// write lock to synchronize concurrent 'chaincode install' operations with ledger creation/open
61
56
m .rwlock .Lock ()
62
57
defer m .rwlock .Unlock ()
63
- m .ccLifecycleListeners [ledgerid ] = l
58
+ m .ccLifecycleListeners [ledgerid ] = append ( m . ccLifecycleListeners [ ledgerid ], l )
64
59
}
65
60
66
61
// HandleChaincodeDeploy is expected to be invoked when a chaincode is deployed via a deploy transaction
@@ -73,11 +68,8 @@ func (m *Mgr) Register(ledgerid string, l ChaincodeLifecycleEventListener) {
73
68
// in this stored `chaincodeDefinitions`
74
69
func (m * Mgr ) HandleChaincodeDeploy (chainid string , chaincodeDefinitions []* ChaincodeDefinition ) error {
75
70
logger .Debugf ("Channel [%s]: Handling chaincode deploy event for chaincode [%s]" , chainid , chaincodeDefinitions )
76
- // Read lock to allow concurrent deploy on multiple channels but to synchronize concurrent `chaincode insall ` operation
71
+ // Read lock to allow concurrent deploy on multiple channels but to synchronize concurrent `chaincode install ` operation
77
72
m .rwlock .RLock ()
78
- defer m .rwlock .RUnlock ()
79
- // TODO, device a mechanism to cleanup entries in this map
80
- m .latestChaincodeDeploys [chainid ] = chaincodeDefinitions
81
73
for _ , chaincodeDefinition := range chaincodeDefinitions {
82
74
installed , dbArtifacts , err := m .infoProvider .RetrieveChaincodeArtifacts (chaincodeDefinition )
83
75
if err != nil {
@@ -88,6 +80,7 @@ func (m *Mgr) HandleChaincodeDeploy(chainid string, chaincodeDefinitions []*Chai
88
80
chainid , chaincodeDefinition )
89
81
continue
90
82
}
83
+ m .callbackStatus .setDeployPending (chainid )
91
84
if err := m .invokeHandler (chainid , chaincodeDefinition , dbArtifacts ); err != nil {
92
85
logger .Warningf ("Channel [%s]: Error while invoking a listener for handling chaincode install event: %s" , chainid , err )
93
86
return err
@@ -97,28 +90,35 @@ func (m *Mgr) HandleChaincodeDeploy(chainid string, chaincodeDefinitions []*Chai
97
90
return nil
98
91
}
99
92
100
- // HandleChaincodeInstall is expected to gets invoked when a during installation of a chaincode package
93
+ // ChaincodeDeployDone is expected to be called when the deploy transaction state is committed
94
+ func (m * Mgr ) ChaincodeDeployDone (chainid string ) {
95
+ // release the lock aquired in function `HandleChaincodeDeploy`
96
+ defer m .rwlock .RUnlock ()
97
+ if m .callbackStatus .isDeployPending (chainid ) {
98
+ m .invokeDoneOnHandlers (chainid , true )
99
+ m .callbackStatus .unsetDeployPending (chainid )
100
+ }
101
+ }
102
+
103
+ // HandleChaincodeInstall is expected to get invoked during installation of a chaincode package
101
104
func (m * Mgr ) HandleChaincodeInstall (chaincodeDefinition * ChaincodeDefinition , dbArtifacts []byte ) error {
102
105
logger .Debugf ("HandleChaincodeInstall() - chaincodeDefinition=%#v" , chaincodeDefinition )
103
106
// Write lock prevents concurrent deploy operations
104
107
m .rwlock .Lock ()
105
- defer m .rwlock .Unlock ()
106
108
for chainid := range m .ccLifecycleListeners {
107
109
logger .Debugf ("Channel [%s]: Handling chaincode install event for chaincode [%s]" , chainid , chaincodeDefinition )
108
110
var deployed bool
109
111
var err error
110
- deployed = m .isChaincodePresentInLatestDeploys (chainid , chaincodeDefinition )
111
- if ! deployed {
112
- if deployed , err = m .infoProvider .IsChaincodeDeployed (chainid , chaincodeDefinition ); err != nil {
113
- logger .Warningf ("Channel [%s]: Error while getting the deployment status of chaincode: %s" , chainid , err )
114
- return err
115
- }
112
+ if deployed , err = m .infoProvider .IsChaincodeDeployed (chainid , chaincodeDefinition ); err != nil {
113
+ logger .Warningf ("Channel [%s]: Error while getting the deployment status of chaincode: %s" , chainid , err )
114
+ return err
116
115
}
117
116
if ! deployed {
118
117
logger .Debugf ("Channel [%s]: Chaincode [%s] is not deployed on channel hence not creating chaincode artifacts." ,
119
118
chainid , chaincodeDefinition )
120
119
continue
121
120
}
121
+ m .callbackStatus .setInstallPending (chainid )
122
122
if err := m .invokeHandler (chainid , chaincodeDefinition , dbArtifacts ); err != nil {
123
123
logger .Warningf ("Channel [%s]: Error while invoking a listener for handling chaincode install event: %s" , chainid , err )
124
124
return err
@@ -128,23 +128,77 @@ func (m *Mgr) HandleChaincodeInstall(chaincodeDefinition *ChaincodeDefinition, d
128
128
return nil
129
129
}
130
130
131
- func (m * Mgr ) isChaincodePresentInLatestDeploys (chainid string , chaincodeDefinition * ChaincodeDefinition ) bool {
132
- ccDefs , ok := m .latestChaincodeDeploys [chainid ]
133
- if ! ok {
134
- return false
131
+ // ChaincodeInstallDone is expected to get invoked when chaincode install finishes
132
+ func (m * Mgr ) ChaincodeInstallDone (succeeded bool ) {
133
+ // release the lock acquired in function `HandleChaincodeInstall`
134
+ defer m .rwlock .Unlock ()
135
+ for chainid := range m .callbackStatus .installPending {
136
+ m .invokeDoneOnHandlers (chainid , succeeded )
137
+ m .callbackStatus .unsetInstallPending (chainid )
135
138
}
136
- for _ , ccDef := range ccDefs {
137
- if ccDef .Name == chaincodeDefinition .Name && ccDef .Version == chaincodeDefinition .Version && bytes .Equal (ccDef .Hash , chaincodeDefinition .Hash ) {
138
- return true
139
+ }
140
+
141
+ func (m * Mgr ) invokeHandler (chainid string , chaincodeDefinition * ChaincodeDefinition , dbArtifactsTar []byte ) error {
142
+ listeners := m .ccLifecycleListeners [chainid ]
143
+ for _ , listener := range listeners {
144
+ if err := listener .HandleChaincodeDeploy (chaincodeDefinition , dbArtifactsTar ); err != nil {
145
+ return err
139
146
}
140
147
}
141
- return false
148
+ return nil
142
149
}
143
150
144
- func (m * Mgr ) invokeHandler (chainid string , chaincodeDefinition * ChaincodeDefinition , dbArtifactsTar [] byte ) error {
145
- listener := m .ccLifecycleListeners [chainid ]
146
- if listener == nil {
147
- return nil
151
+ func (m * Mgr ) invokeDoneOnHandlers (chainid string , succeeded bool ) {
152
+ listeners := m .ccLifecycleListeners [chainid ]
153
+ for _ , listener := range listeners {
154
+ listener . ChaincodeDeployDone ( succeeded )
148
155
}
149
- return listener .HandleChaincodeDeploy (chaincodeDefinition , dbArtifactsTar )
156
+ }
157
+
158
+ type callbackStatus struct {
159
+ l sync.Mutex
160
+ deployPending map [string ]bool
161
+ installPending map [string ]bool
162
+ }
163
+
164
+ func newCallbackStatus () * callbackStatus {
165
+ return & callbackStatus {
166
+ deployPending : make (map [string ]bool ),
167
+ installPending : make (map [string ]bool )}
168
+ }
169
+
170
+ func (s * callbackStatus ) setDeployPending (channelID string ) {
171
+ s .l .Lock ()
172
+ defer s .l .Unlock ()
173
+ s .deployPending [channelID ] = true
174
+ }
175
+
176
+ func (s * callbackStatus ) unsetDeployPending (channelID string ) {
177
+ s .l .Lock ()
178
+ defer s .l .Unlock ()
179
+ delete (s .deployPending , channelID )
180
+ }
181
+
182
+ func (s * callbackStatus ) isDeployPending (channelID string ) bool {
183
+ s .l .Lock ()
184
+ defer s .l .Unlock ()
185
+ return s .deployPending [channelID ]
186
+ }
187
+
188
+ func (s * callbackStatus ) setInstallPending (channelID string ) {
189
+ s .l .Lock ()
190
+ defer s .l .Unlock ()
191
+ s .installPending [channelID ] = true
192
+ }
193
+
194
+ func (s * callbackStatus ) unsetInstallPending (channelID string ) {
195
+ s .l .Lock ()
196
+ defer s .l .Unlock ()
197
+ delete (s .installPending , channelID )
198
+ }
199
+
200
+ func (s * callbackStatus ) isInstallPending (channelID string ) bool {
201
+ s .l .Lock ()
202
+ defer s .l .Unlock ()
203
+ return s .installPending [channelID ]
150
204
}
0 commit comments