@@ -48,6 +48,7 @@ import (
4848 "os"
4949 "strconv"
5050 "strings"
51+ "sync"
5152
5253 mq "github.com/ibm-messaging/mq-golang/v5/ibmmq"
5354
6465 otelInit = false // Has the module been initialised
6566 otelEnabled = false // Are we going to actually do any OTel work
6667
67- objectHandleMap = make (map [string ]* mq.MQMessageHandle )
68- objectOptionsMap = make (map [string ]* propOptions )
68+ objectMapHandle = make (map [string ]* mq.MQMessageHandle )
69+ objectMapOptions = make (map [string ]* propOptions )
70+
71+ omh sync.Mutex
72+ omo sync.Mutex
6973)
7074
7175const (
@@ -93,6 +97,23 @@ func init() {
9397 os .Setenv ("AMQ_OTEL_INSTRUMENTED" , "true" )
9498}
9599
100+ // Go's locks are not concurrently accessible. So we need to add locks. This might not be required for
101+ // all operations, but better to be safe. These are trivial functions, but we might want to add tracing/debug
102+ // occasionally. So it's better to wrap the real calls.
103+ func lockMapOptions () {
104+ omo .Lock ()
105+ }
106+ func unlockMapOptions () {
107+ omo .Unlock ()
108+ }
109+
110+ func lockMapHandle () {
111+ omh .Lock ()
112+ }
113+ func unlockMapHandle () {
114+ omh .Unlock ()
115+ }
116+
96117// This is the function that applications have to call, to ensure the OTel
97118// interface is available.
98119func Setup () {
@@ -142,30 +163,37 @@ func objectKey(hc *mq.MQQueueManager, ho *mq.MQObject) string {
142163// Do we have a MsgHandle for this hConn? If not, create a new one
143164func getMsgHandle (hConn * mq.MQQueueManager , hObj * mq.MQObject ) * mq.MQMessageHandle {
144165 key := objectKey (hConn , hObj )
145- if _ , ok := objectHandleMap [key ]; ! ok {
166+ lockMapHandle ()
167+ if _ , ok := objectMapHandle [key ]; ! ok {
146168
147169 cmho := mq .NewMQCMHO ()
148170 mh , err := hConn .CrtMH (cmho )
149171 if err == nil {
150- objectHandleMap [key ] = & mh
172+ objectMapHandle [key ] = & mh
151173 } else {
152174 fmt .Printf (err .Error ())
153175 }
154176
155177 }
156- return objectHandleMap [key ]
178+
179+ o := objectMapHandle [key ]
180+ unlockMapHandle ()
181+
182+ return o
157183}
158184
159185// Is the GMO/PMO MsgHandle one that we allocated?
160186func compareMsgHandle (hConn * mq.MQQueueManager , hObj * mq.MQObject , mh * mq.MQMessageHandle ) bool {
161187 rc := false
162188 key := objectKey (hConn , hObj )
163- if oh , ok := objectHandleMap [key ]; ok {
189+ lockMapHandle ()
190+ if oh , ok := objectMapHandle [key ]; ok {
164191 mhLocal := oh
165192 if mhLocal .GetValue () == mh .GetValue () {
166193 rc = true
167194 }
168195 }
196+ unlockMapHandle ()
169197 return rc
170198}
171199
@@ -218,20 +246,24 @@ func otelDisc(qMgr *mq.MQQueueManager) {
218246 // the hConn value. As this is MQDISC, we don't care about
219247 // any specific hObj
220248 prefix := fmt .Sprintf ("%d/" , qMgr .GetValue ())
221- for k , mh := range objectHandleMap {
249+ lockMapHandle ()
250+ for k , mh := range objectMapHandle {
222251 if strings .HasPrefix (k , prefix ) {
223252 dmho := mq .NewMQDMHO ()
224253 mh .DltMH (dmho )
225- delete (objectHandleMap , k )
254+ delete (objectMapHandle , k )
226255 }
227256 }
257+ unlockMapHandle ()
228258
229259 // And delete information about any OPENed object too
230- for k , _ := range objectOptionsMap {
260+ lockMapOptions ()
261+ for k , _ := range objectMapOptions {
231262 if strings .HasPrefix (k , prefix ) {
232- delete (objectOptionsMap , k )
263+ delete (objectMapOptions , k )
233264 }
234265 }
266+ unlockMapOptions ()
235267
236268 traceExit ("disc" )
237269 return
@@ -309,7 +341,9 @@ func otelOpen(hObj *mq.MQObject, od *mq.MQOD, openOptions int32) {
309341 // Create an object to hold the discovered value
310342 options := propOptions {propCtl : propCtl }
311343 // replace any existing value for this object handle
312- objectOptionsMap [key ] = & options
344+ lockMapOptions ()
345+ objectMapOptions [key ] = & options
346+ unlockMapOptions ()
313347
314348 } else {
315349 logTrace ("open: not doing Inquire" )
@@ -324,7 +358,9 @@ func otelClose(hObj *mq.MQObject) {
324358 traceEntry ("close" )
325359
326360 key := objectKey (hObj .GetHConn (), hObj )
327- delete (objectOptionsMap , key )
361+ lockMapOptions ()
362+ delete (objectMapOptions , key )
363+ unlockMapOptions ()
328364
329365 traceExit ("close" )
330366 return
@@ -506,12 +542,14 @@ func otelGetTraceBefore(otelOpts mq.OtelOpts, hConn *mq.MQQueueManager, hObj *mq
506542 } else {
507543 key := objectKey (hConn , hObj )
508544 propCtl = - 1
509- if opts , ok := objectOptionsMap [key ]; ok {
545+ lockMapOptions ()
546+ if opts , ok := objectMapOptions [key ]; ok {
510547 propCtl = opts .propCtl
511548 // Stash the GMO options so they can be restored afterwards
512549 opts .gmo = gogmo .Options
513- objectOptionsMap [key ] = opts
550+ objectMapOptions [key ] = opts
514551 }
552+ unlockMapOptions ()
515553
516554 // If we know that the app or queue is configured for not returning any properties, then we will override that into our handle
517555 if (propGetOptions == mq .MQGMO_NO_PROPERTIES ) || (propGetOptions == mq .MQGMO_PROPERTIES_AS_Q_DEF && propCtl == mq .MQPROP_NONE ) {
@@ -594,11 +632,13 @@ func otelGetTraceAfter(otelOpts mq.OtelOpts, hObj *mq.MQObject, gogmo *mq.MQGMO,
594632 if ! async && compareMsgHandle (hc , ho , & mh ) {
595633 gogmo .MsgHandle = mq.MQMessageHandle {}
596634 key := objectKey (hc , ho )
597- if opts , ok := objectOptionsMap [key ]; ok {
635+ lockMapOptions ()
636+ if opts , ok := objectMapOptions [key ]; ok {
598637 gogmo .Options = opts .gmo
599638 } else {
600639 gogmo .Options &= ^ mq .MQGMO_PROPERTIES_IN_HANDLE
601640 }
641+ unlockMapOptions ()
602642 logTrace ("Removing our handle: hObj %v" , hObj )
603643 }
604644
0 commit comments