diff --git a/field_map.go b/field_map.go index 18216f81c..f17fae9ff 100644 --- a/field_map.go +++ b/field_map.go @@ -128,6 +128,16 @@ func (m FieldMap) GetBytes(tag Tag) ([]byte, MessageRejectError) { return f[0].value, nil } +// getBytesNoLock is a lock free zero-copy GetField wrapper for []bytes fields. +func (m FieldMap) getBytesNoLock(tag Tag) ([]byte, MessageRejectError) { + f, ok := m.tagLookup[tag] + if !ok { + return nil, ConditionallyRequiredFieldMissing(tag) + } + + return f[0].value, nil +} + // GetBool is a GetField wrapper for bool fields. func (m FieldMap) GetBool(tag Tag) (bool, MessageRejectError) { var val FIXBoolean @@ -152,6 +162,21 @@ func (m FieldMap) GetInt(tag Tag) (int, MessageRejectError) { return int(val), err } +// GetInt is a lock free GetField wrapper for int fields. +func (m FieldMap) getIntNoLock(tag Tag) (int, MessageRejectError) { + bytes, err := m.getBytesNoLock(tag) + if err != nil { + return 0, err + } + + var val FIXInt + if val.Read(bytes) != nil { + err = IncorrectDataFormatForValue(tag) + } + + return int(val), err +} + // GetTime is a GetField wrapper for utc timestamp fields. func (m FieldMap) GetTime(tag Tag) (t time.Time, err MessageRejectError) { m.rwLock.RLock() @@ -263,9 +288,6 @@ func (m *FieldMap) CopyInto(to *FieldMap) { } func (m *FieldMap) add(f field) { - m.rwLock.Lock() - defer m.rwLock.Unlock() - t := fieldTag(f) if _, ok := m.tagLookup[t]; !ok { m.tags = append(m.tags, t) diff --git a/message.go b/message.go index 11afd7669..75faeb85a 100644 --- a/message.go +++ b/message.go @@ -186,6 +186,13 @@ func doParsing(mp *msgParser) (err error) { mp.msg.Body.Clear() mp.msg.Trailer.Clear() + mp.msg.Header.rwLock.Lock() + defer mp.msg.Header.rwLock.Unlock() + mp.msg.Body.rwLock.Lock() + defer mp.msg.Body.rwLock.Unlock() + mp.msg.Trailer.rwLock.Lock() + defer mp.msg.Trailer.rwLock.Unlock() + // Allocate expected message fields in one chunk. fieldCount := 0 for _, b := range mp.rawBytes { @@ -267,7 +274,7 @@ func doParsing(mp *msgParser) (err error) { } if mp.parsedFieldBytes.tag == tagXMLDataLen { - xmlDataLen, _ = mp.msg.Header.GetInt(tagXMLDataLen) + xmlDataLen, _ = mp.msg.Header.getIntNoLock(tagXMLDataLen) } mp.fieldIndex++ } @@ -292,7 +299,7 @@ func doParsing(mp *msgParser) (err error) { } } - bodyLength, err := mp.msg.Header.GetInt(tagBodyLength) + bodyLength, err := mp.msg.Header.getIntNoLock(tagBodyLength) if err != nil { err = parseError{OrigError: err.Error()} } else if length != bodyLength && !xmlDataMsg {