quickfix
quickfix copied to clipboard
concurrent map read and map write
Hello, sometime I receive concurrent read & write error when I try to log the whole struct or just a single value. I don't modify structs I received from quickfix, just read them.
fatal error: concurrent map read and map write
goroutine 51 [running]:
runtime.throw(0x497c353, 0x21)
/usr/local/opt/go/libexec/src/runtime/panic.go:605 +0x95 fp=0xc4201d59b8 sp=0xc4201d5998 pc=0x402c9b5
runtime.mapaccess2_fast64(0x4857f80, 0xc420146960, 0x6, 0x1, 0x5f10028)
/usr/local/opt/go/libexec/src/runtime/hashmap_fast.go:168 +0x1b7 fp=0xc4201d59e0 sp=0xc4201d59b8 pc=0x400e0e7
metabreak/vendor/github.com/quickfixgo/quickfix.FieldMap.GetField(0xc420146960, 0xc420074200, 0x16, 0x20, 0x498c898, 0x6, 0x5f10028, 0xc42019c1a0, 0x490d440, 0x1)
/Users/wb/dev/go/src/metabreak/vendor/github.com/quickfixgo/quickfix/field_map.go:79 +0x48 fp=0xc4201d5a48 sp=0xc4201d59e0 pc=0x42391e8
metabreak/vendor/github.com/quickfixgo/quickfix.FieldMap.Get(0xc420146960, 0xc420074200, 0x16, 0x20, 0x498c898, 0x517fee0, 0xc42019c1a0, 0x0, 0x0)
/Users/wb/dev/go/src/metabreak/vendor/github.com/quickfixgo/quickfix/field_map.go:68 +0xb8 fp=0xc4201d5ab0 sp=0xc4201d5a48 pc=0x4239108
metabreak/vendor/github.com/quickfixgo/fix44/executionreport.ExecutionReport.GetAvgPx(0xc420166270, 0xc4201662c0, 0xc420166298, 0xc420166270, 0xc4201a2329, 0x1, 0x0, 0x0)
/Users/wb/dev/go/src/metabreak/vendor/github.com/quickfixgo/fix44/executionreport/ExecutionReport.generated.go:1165 +0x79 fp=0xc4201d5b10 sp=0xc4201d5ab0 pc=0x440a809
metabreak/fix.state.trade(0xc4200414d0, 0xc420076360, 0xc4200763c0, 0xc420076420, 0xc420076480)
/Users/wb/dev/go/src/metabreak/fix/dumb.go:85 +0x807 fp=0xc4201d5fb8 sp=0xc4201d5b10 pc=0x46468f7
runtime.goexit()
/usr/local/opt/go/libexec/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc4201d5fc0 sp=0xc4201d5fb8 pc=0x4059b91
created by metabreak/fix.Dumb
/Users/wb/dev/go/src/metabreak/fix/dumb.go:59 +0x407
case rep := <-s.execrep:
clOrdID, _ := rep.GetClOrdID()
avgPx, _ := rep.GetAvgPx()
ordStatus, _ := rep.GetOrdStatus()
netMoney, _ := rep.GetNetMoney() // here is dumb:85
transactTime, _ := rep.GetTransactTime()
rejectReason, _ := rep.GetOrdRejReason()
execType, _ := rep.GetExecType()
It happens from time to time, in various places involving quickfix struct values reads.
Can you try re-running with the -race
option? This should help pinpoint where this is happening.
@cbusbey hello, I also met this issue.
I think the reason is that Maps are not safe for concurrent use.
Please help to confirm, thanks a lot!
type FieldMap struct { tagLookup map[Tag]field tagSort }
Maps are not safe for concurrent use. As FieldMaps are basically an embedded map, FieldMaps are also not safe for concurrent use.
Maps are not safe for concurrent use. As FieldMaps are basically an embedded map, FieldMaps are also not safe for concurrent use.
Then why not to fix this? Currently it's impossible to write asynchronous applications with this lib out of the box.
I'm also experiencing an intermittent panic around concurrent map access, but within store.go
, line 99:
func (store memoryStore) GetMessages(beginSeqNum, endSeqNum int) ([][]byte, error) {
var msgs [][]byte
for seqNum := beginSeqNum; seqNum <= endSeqNum; seqNum++ {
if m, ok := store.messageMap[seqNum]; ok {
msgs = append(msgs, m)
}
}
return msgs, nil
}
I just have a simple test acceptor
that spits out the received messages to a table, and a test initiator
that reads 1k messages from a raw FIX file, and pumps them onto the connection.
I'm not doing anything concurrent, just a line reader:
scanner := bufio.NewScanner(file)
for scanner.Scan() {
msg := quickfix.NewMessage()
buf := bytes.NewBuffer(scanner.Bytes())
err := quickfix.ParseMessage(msg, buf)
checkErr(err)
err = quickfix.Send(msg)
checkErr(err)
}
Simply adding in a delay <-time.After(5 * time.Millisecond)
within the above for
loop seems to alleviate it.
Seems like the memorystore
's internal map should be safe for concurrent use?
UPDATE For my particular case, I believe it's caused by the fact that there are 2 separate SenderCompID's within my file, and it looks like those are handled within separate go routines within quickfix.
MarketDataIncrementalRefresh callback func There is a blocking problem
The data is delayed and cannot be processed concurrently.
Is there any good solution? @cbusbey
Ran into this today, had issues using the quickfix.Message after I had received it from a channel - still have to investigate what quickfix was is doing with the message after it is received in the FromApp(...) function.
Workaround was to send a copy of the message like so.
original := newordersingle.New(...) // or wherever you get the message from
temp := new(quickfix.Message)
original.CopyInto(temp)
copy := newordersingle.FromMessage(temp)
outchan <- copy
✌️