Skip to content

Implementing uint64 SeqNums #708

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions _sql/mssql/quickfix_database.sql
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ CREATE TABLE sessions (
targetlocid VARCHAR(64) NOT NULL,
session_qualifier VARCHAR(64) NOT NULL,
creation_time DATETIME NOT NULL,
incoming_seqnum INT NOT NULL,
outgoing_seqnum INT NOT NULL,
incoming_seqnum BIGINT NOT NULL,
outgoing_seqnum BIGINT NOT NULL,
PRIMARY KEY (beginstring, sendercompid, sendersubid, senderlocid,
targetcompid, targetsubid, targetlocid, session_qualifier)
);
Expand All @@ -27,7 +27,7 @@ CREATE TABLE messages (
targetsubid VARCHAR(64) NOT NULL,
targetlocid VARCHAR(64) NOT NULL,
session_qualifier VARCHAR(64) NOT NULL,
msgseqnum INT NOT NULL,
msgseqnum BIGINT NOT NULL,
message TEXT NOT NULL,
PRIMARY KEY (beginstring, sendercompid, sendersubid, senderlocid,
targetcompid, targetsubid, targetlocid, session_qualifier,
Expand Down
2 changes: 1 addition & 1 deletion _sql/mysql/messages_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ CREATE TABLE messages (
targetsubid VARCHAR(64) NOT NULL,
targetlocid VARCHAR(64) NOT NULL,
session_qualifier VARCHAR(64) NOT NULL,
msgseqnum INT NOT NULL,
msgseqnum BIGINT NOT NULL,
message TEXT NOT NULL,
PRIMARY KEY (beginstring, sendercompid, sendersubid, senderlocid,
targetcompid, targetsubid, targetlocid, session_qualifier,
Expand Down
4 changes: 2 additions & 2 deletions _sql/mysql/sessions_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ CREATE TABLE sessions (
targetlocid VARCHAR(64) NOT NULL,
session_qualifier VARCHAR(64) NOT NULL,
creation_time DATETIME NOT NULL,
incoming_seqnum INT NOT NULL,
outgoing_seqnum INT NOT NULL,
incoming_seqnum BIGINT NOT NULL,
outgoing_seqnum BIGINT NOT NULL,
PRIMARY KEY (beginstring, sendercompid, sendersubid, senderlocid,
targetcompid, targetsubid, targetlocid, session_qualifier)
);
2 changes: 1 addition & 1 deletion _sql/oracle/messages_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ CREATE TABLE messages (
targetsubid VARCHAR2(64) NOT NULL,
targetlocid VARCHAR2(64) NOT NULL,
session_qualifier VARCHAR2(64) NOT NULL,
msgseqnum INTEGER NOT NULL,
msgseqnum BIGINT NOT NULL,
message VARCHAR2(4000) NOT NULL,
PRIMARY KEY (beginstring, sendercompid, sendersubid, senderlocid,
targetcompid, targetsubid, targetlocid, session_qualifier, msgseqnum)
Expand Down
4 changes: 2 additions & 2 deletions _sql/oracle/sessions_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ CREATE TABLE sessions (
targetlocid VARCHAR2(64) NOT NULL,
session_qualifier VARCHAR2(64) NOT NULL,
creation_time TIMESTAMP NOT NULL,
incoming_seqnum INTEGER NOT NULL,
outgoing_seqnum INTEGER NOT NULL,
incoming_seqnum BIGINT NOT NULL,
outgoing_seqnum BIGINT NOT NULL,
PRIMARY KEY (beginstring, sendercompid, sendersubid, senderlocid,
targetcompid, targetsubid, targetlocid, session_qualifier)
);
2 changes: 1 addition & 1 deletion _sql/postgresql/messages_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ CREATE TABLE messages (
targetsubid VARCHAR(64) NOT NULL,
targetlocid VARCHAR(64) NOT NULL,
session_qualifier VARCHAR(64) NOT NULL,
msgseqnum INTEGER NOT NULL,
msgseqnum BIGINT NOT NULL,
message TEXT NOT NULL,
PRIMARY KEY (beginstring, sendercompid, sendersubid, senderlocid,
targetcompid, targetsubid, targetlocid, session_qualifier,
Expand Down
4 changes: 2 additions & 2 deletions _sql/postgresql/sessions_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ CREATE TABLE sessions (
targetlocid VARCHAR(64) NOT NULL,
session_qualifier VARCHAR(64) NOT NULL,
creation_time TIMESTAMP WITH TIME ZONE NOT NULL,
incoming_seqnum INTEGER NOT NULL,
outgoing_seqnum INTEGER NOT NULL,
incoming_seqnum BIGINT NOT NULL,
outgoing_seqnum BIGINT NOT NULL,
PRIMARY KEY (beginstring, sendercompid, sendersubid, senderlocid,
targetcompid, targetsubid, targetlocid, session_qualifier)
);
2 changes: 1 addition & 1 deletion _sql/sqlite3/messages_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ CREATE TABLE messages (
targetsubid VARCHAR(64) NOT NULL,
targetlocid VARCHAR(64) NOT NULL,
session_qualifier VARCHAR(64) NOT NULL,
msgseqnum INT NOT NULL,
msgseqnum BIGINT NOT NULL,
message TEXT NOT NULL,
PRIMARY KEY (beginstring, sendercompid, sendersubid, senderlocid,
targetcompid, targetsubid, targetlocid, session_qualifier,
Expand Down
4 changes: 2 additions & 2 deletions _sql/sqlite3/sessions_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ CREATE TABLE sessions (
targetlocid VARCHAR(64) NOT NULL,
session_qualifier VARCHAR(64) NOT NULL,
creation_time DATETIME NOT NULL,
incoming_seqnum INT NOT NULL,
outgoing_seqnum INT NOT NULL,
incoming_seqnum BIGINT NOT NULL,
outgoing_seqnum BIGINT NOT NULL,
PRIMARY KEY (beginstring, sendercompid, sendersubid, senderlocid,
targetcompid, targetsubid, targetlocid, session_qualifier)
);
4 changes: 2 additions & 2 deletions _test/test-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func main() {
}
num, ok := queryParams["NEXTTARGETSEQNUM"]
if ok {
seqnumInt, cErr := strconv.Atoi(num[0])
seqnumInt, cErr := strconv.ParseUint(num[0], 10, 64)
if cErr != nil {
fmt.Println("cannot find seqnum")
os.Exit(1)
Expand All @@ -216,7 +216,7 @@ func main() {

num, ok = queryParams["NEXTSENDERSEQNUM"]
if ok {
seqnumInt, cErr := strconv.Atoi(num[0])
seqnumInt, cErr := strconv.ParseUint(num[0], 10, 64)
if cErr != nil {
fmt.Println("cannot find seqnum")
os.Exit(1)
Expand Down
21 changes: 21 additions & 0 deletions field_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,21 @@ func (m FieldMap) GetInt(tag Tag) (int, MessageRejectError) {
return int(val), err
}

// GetInt is a GetField wrapper for int fields.
func (m FieldMap) GetUint64(tag Tag) (uint64, MessageRejectError) {
bytes, err := m.GetBytes(tag)
if err != nil {
return 0, err
}

var val FIXUint64
if val.Read(bytes) != nil {
err = IncorrectDataFormatForValue(tag)
}

return uint64(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)
Expand Down Expand Up @@ -270,6 +285,12 @@ func (m *FieldMap) SetInt(tag Tag, value int) *FieldMap {
return m.SetBytes(tag, v.Write())
}

// SetUint64 is a SetField wrapper for int fields.
func (m *FieldMap) SetUint64(tag Tag, value uint64) *FieldMap {
v := FIXUint64(value)
return m.SetBytes(tag, v.Write())
}

// SetString is a SetField wrapper for string fields.
func (m *FieldMap) SetString(tag Tag, value string) *FieldMap {
return m.SetBytes(tag, []byte(value))
Expand Down
59 changes: 59 additions & 0 deletions fix_uint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) quickfixengine.org All rights reserved.
//
// This file may be distributed under the terms of the quickfixengine.org
// license as defined by quickfixengine.org and appearing in the file
// LICENSE included in the packaging of this file.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE.
//
// See http://www.quickfixengine.org/LICENSE for licensing information.
//
// Contact [email protected] if any conditions of this licensing
// are not clear to you.

package quickfix

import (
"errors"
"strconv"
)

// parseUInt is similar to the function in strconv, but is tuned for uint64s appearing in FIX field types.
func parseUInt64(d []byte) (n uint64, err error) {
if len(d) == 0 {
err = errors.New("empty bytes")
return
}

for _, dec := range d {
if dec < ascii0 || dec > ascii9 {
err = errors.New("invalid format")
return
}

n = n*10 + (uint64(dec) - ascii0)
}

return
}

// FIXUInt64 is a FIX Uint64 Value, implements FieldValue.
type FIXUint64 uint64

// Uint64 converts the FIXUint64 value to uint64.
func (f FIXUint64) Uint64() uint64 { return uint64(f) }

func (f *FIXUint64) Read(bytes []byte) error {
i, err := parseUInt64(bytes)
if err != nil {
return err
}
*f = FIXUint64(i)
return nil
}

func (f FIXUint64) Write() []byte {
return strconv.AppendInt(nil, int64(f), 10)
}
52 changes: 52 additions & 0 deletions fix_uint_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) quickfixengine.org All rights reserved.
//
// This file may be distributed under the terms of the quickfixengine.org
// license as defined by quickfixengine.org and appearing in the file
// LICENSE included in the packaging of this file.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE.
//
// See http://www.quickfixengine.org/LICENSE for licensing information.
//
// Contact [email protected] if any conditions of this licensing
// are not clear to you.

package quickfix

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestFIXUInt_Write(t *testing.T) {
field := FIXUint64(5)

assert.Equal(t, "5", string(field.Write()))
}

func TestFIXUInt_Read(t *testing.T) {
var field FIXUint64
err := field.Read([]byte("15"))
assert.Nil(t, err, "Unexpected error")
assert.Equal(t, uint64(15), uint64(field))

err = field.Read([]byte("blah"))
assert.NotNil(t, err, "Unexpected error")
}

func TestFIXUInt_UInt(t *testing.T) {
f := FIXUint64(4)
assert.Equal(t, uint64(4), f.Uint64())
}

func BenchmarkFIXUInt_Read(b *testing.B) {
intBytes := []byte("1500")
var field FIXUint64

for i := 0; i < b.N; i++ {
_ = field.Read(intBytes)
}
}
14 changes: 7 additions & 7 deletions in_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func (state inSession) handleSequenceReset(session *session, msg *Message) (next

switch {
case newSeqNo > expectedSeqNum:
if err := session.store.SetNextTargetMsgSeqNum(int(newSeqNo)); err != nil {
if err := session.store.SetNextTargetMsgSeqNum(uint64(newSeqNo)); err != nil {
return handleStateError(session, err)
}
case newSeqNo < expectedSeqNum:
Expand Down Expand Up @@ -196,7 +196,7 @@ func (state inSession) handleResendRequest(session *session, msg *Message) (next
return state.processReject(session, msg, RequiredTagMissing(tagEndSeqNo))
}

endSeqNo := int(endSeqNoField)
endSeqNo := uint64(endSeqNoField)

session.log.OnEventf("Received ResendRequest FROM: %d TO: %d", beginSeqNo, endSeqNo)
expectedSeqNum := session.store.NextSenderMsgSeqNum()
Expand All @@ -207,7 +207,7 @@ func (state inSession) handleResendRequest(session *session, msg *Message) (next
endSeqNo = expectedSeqNum - 1
}

if err := state.resendMessages(session, int(beginSeqNo), endSeqNo, *msg); err != nil {
if err := state.resendMessages(session, uint64(beginSeqNo), endSeqNo, *msg); err != nil {
return handleStateError(session, err)
}

Expand All @@ -225,7 +225,7 @@ func (state inSession) handleResendRequest(session *session, msg *Message) (next
return state
}

func (state inSession) resendMessages(session *session, beginSeqNo, endSeqNo int, inReplyTo Message) error {
func (state inSession) resendMessages(session *session, beginSeqNo, endSeqNo uint64, inReplyTo Message) error {
if session.DisableMessagePersist {
return state.generateSequenceReset(session, beginSeqNo, endSeqNo+1, inReplyTo)
}
Expand All @@ -240,7 +240,7 @@ func (state inSession) resendMessages(session *session, beginSeqNo, endSeqNo int
return err // We cant continue with a message that cant be parsed correctly.
}
msgType, _ := msg.Header.GetBytes(tagMsgType)
sentMessageSeqNum, _ := msg.Header.GetInt(tagMsgSeqNum)
sentMessageSeqNum, _ := msg.Header.GetUint64(tagMsgSeqNum)

if isAdminMessageType(msgType) {
nextSeqNum = sentMessageSeqNum + 1
Expand Down Expand Up @@ -297,7 +297,7 @@ func (state inSession) processReject(session *session, msg *Message, rej Message
}

if nextState.messageStash == nil {
nextState.messageStash = make(map[int]*Message)
nextState.messageStash = make(map[uint64]*Message)
}

nextState.messageStash[TypedError.ReceivedTarget] = msg
Expand Down Expand Up @@ -387,7 +387,7 @@ func (state inSession) doTargetTooLow(session *session, msg *Message, rej target
return state
}

func (state *inSession) generateSequenceReset(session *session, beginSeqNo int, endSeqNo int, inReplyTo Message) (err error) {
func (state *inSession) generateSequenceReset(session *session, beginSeqNo uint64, endSeqNo uint64, inReplyTo Message) (err error) {
sequenceReset := NewMessage()
session.fillDefaultHeader(sequenceReset, &inReplyTo)

Expand Down
4 changes: 2 additions & 2 deletions in_session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ func (s *InSessionTestSuite) TestFIXMsgInTargetTooHigh() {
}
func (s *InSessionTestSuite) TestFIXMsgInTargetTooHighResendRequestChunkSize() {
var tests = []struct {
chunkSize int
expectedEndSeqNo int
chunkSize uint64
expectedEndSeqNo uint64
}{
{0, 0},
{10, 0},
Expand Down
2 changes: 1 addition & 1 deletion internal/session_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type SessionSettings struct {
HeartBtIntOverride bool
SessionTime *TimeRange
InitiateLogon bool
ResendRequestChunkSize int
ResendRequestChunkSize uint64
EnableLastMsgSeqNumProcessed bool
EnableNextExpectedMsgSeqNum bool
SkipCheckLatency bool
Expand Down
Loading
Loading