From 73fb82bbbbf1522222b7f1cb24a820c974bfb0dc Mon Sep 17 00:00:00 2001 From: Philip Whitehouse Date: Thu, 23 Apr 2020 17:09:25 +0100 Subject: [PATCH 1/4] Optimise session reset to reduce Calendar creation --- .../main/java/quickfix/CachedFileStore.java | 8 ++ .../java/quickfix/DefaultSessionSchedule.java | 24 +++- .../src/main/java/quickfix/FileStore.java | 8 ++ .../src/main/java/quickfix/JdbcStore.java | 4 + .../src/main/java/quickfix/MemoryStore.java | 4 + .../src/main/java/quickfix/MessageStore.java | 9 ++ .../src/main/java/quickfix/NoopStore.java | 6 + .../src/main/java/quickfix/Session.java | 2 +- .../src/main/java/quickfix/SessionState.java | 9 +- .../main/java/quickfix/SleepycatStore.java | 13 ++ .../quickfix/DefaultSessionScheduleTest.java | 120 ++++++++++++++++++ .../src/test/java/quickfix/LogUtilTest.java | 3 +- 12 files changed, 199 insertions(+), 11 deletions(-) create mode 100644 quickfixj-core/src/test/java/quickfix/DefaultSessionScheduleTest.java diff --git a/quickfixj-core/src/main/java/quickfix/CachedFileStore.java b/quickfixj-core/src/main/java/quickfix/CachedFileStore.java index 7a05793915..37941ba97f 100644 --- a/quickfixj-core/src/main/java/quickfix/CachedFileStore.java +++ b/quickfixj-core/src/main/java/quickfix/CachedFileStore.java @@ -163,6 +163,14 @@ public Date getCreationTime() throws IOException { return cache.getCreationTime(); } + /* + * (non-Javadoc) + * @see quickfix.MessageStore#getCreationTimeCalendar() + */ + public Calendar getCreationTimeCalendar() throws IOException { + return cache.getCreationTimeCalendar(); + } + private void initializeSequenceNumbers() throws IOException { sequenceNumberFile.seek(0); if (sequenceNumberFile.length() > 0) { diff --git a/quickfixj-core/src/main/java/quickfix/DefaultSessionSchedule.java b/quickfixj-core/src/main/java/quickfix/DefaultSessionSchedule.java index 83d8bb5eab..184095f87f 100644 --- a/quickfixj-core/src/main/java/quickfix/DefaultSessionSchedule.java +++ b/quickfixj-core/src/main/java/quickfix/DefaultSessionSchedule.java @@ -41,10 +41,17 @@ public class DefaultSessionSchedule implements SessionSchedule { private final int[] weekdayOffsets; protected static final Logger LOG = LoggerFactory.getLogger(DefaultSessionSchedule.class); + //Cache recent time data to reduce creation of calendar objects + private ThreadLocal threadLocalCalendar; + private ThreadLocal threadLocalRecentTimeInterval; + public DefaultSessionSchedule(SessionSettings settings, SessionID sessionID) throws ConfigError, FieldConvertError { + threadLocalCalendar = ThreadLocal.withInitial(SystemTime::getUtcCalendar); + threadLocalRecentTimeInterval = new ThreadLocal<>(); + isNonStopSession = settings.isSetting(sessionID, Session.SETTING_NON_STOP_SESSION) + && settings.getBool(sessionID, Session.SETTING_NON_STOP_SESSION); - isNonStopSession = settings.isSetting(sessionID, Session.SETTING_NON_STOP_SESSION) && settings.getBool(sessionID, Session.SETTING_NON_STOP_SESSION); TimeZone defaultTimeZone = getDefaultTimeZone(settings, sessionID); if (isNonStopSession) { isWeekdaySession = false; @@ -104,7 +111,7 @@ private TimeEndPoint getTimeEndPoint(SessionSettings settings, SessionID session } private TimeZone getDefaultTimeZone(SessionSettings settings, SessionID sessionID) - throws ConfigError, FieldConvertError { + throws ConfigError { TimeZone sessionTimeZone; if (settings.isSetting(sessionID, Session.SETTING_TIMEZONE)) { String sessionTimeZoneID = settings.getString(sessionID, Session.SETTING_TIMEZONE); @@ -300,9 +307,16 @@ public boolean isSessionTime() { if(isNonStopSession()) { return true; } - Calendar now = SystemTime.getUtcCalendar(); - TimeInterval interval = theMostRecentIntervalBefore(now); - return interval.isContainingTime(now); + Calendar now = threadLocalCalendar.get(); + now.setTimeInMillis(SystemTime.currentTimeMillis()); + TimeInterval mostRecentInterval = threadLocalRecentTimeInterval.get(); + if (mostRecentInterval != null && mostRecentInterval.isContainingTime(now)) { + return true; + } + mostRecentInterval = theMostRecentIntervalBefore(now); + boolean result = mostRecentInterval.isContainingTime(now); + threadLocalRecentTimeInterval.set(mostRecentInterval); + return result; } public String toString() { diff --git a/quickfixj-core/src/main/java/quickfix/FileStore.java b/quickfixj-core/src/main/java/quickfix/FileStore.java index 20ec17f585..f9e3068a48 100644 --- a/quickfixj-core/src/main/java/quickfix/FileStore.java +++ b/quickfixj-core/src/main/java/quickfix/FileStore.java @@ -153,6 +153,14 @@ public Date getCreationTime() throws IOException { return cache.getCreationTime(); } + /* (non-Javadoc) + * @see quickfix.MessageStore#getCreationTimeCalendar() + */ + @Override + public Calendar getCreationTimeCalendar() throws IOException { + return cache.getCreationTimeCalendar(); + } + private void initializeSequenceNumbers() throws IOException { senderSequenceNumberFile.seek(0); if (senderSequenceNumberFile.length() > 0) { diff --git a/quickfixj-core/src/main/java/quickfix/JdbcStore.java b/quickfixj-core/src/main/java/quickfix/JdbcStore.java index 1874d0953b..235784e635 100644 --- a/quickfixj-core/src/main/java/quickfix/JdbcStore.java +++ b/quickfixj-core/src/main/java/quickfix/JdbcStore.java @@ -155,6 +155,10 @@ public Date getCreationTime() throws IOException { return cache.getCreationTime(); } + public Calendar getCreationTimeCalendar() throws IOException { + return cache.getCreationTimeCalendar(); + } + public int getNextSenderMsgSeqNum() throws IOException { return cache.getNextSenderMsgSeqNum(); } diff --git a/quickfixj-core/src/main/java/quickfix/MemoryStore.java b/quickfixj-core/src/main/java/quickfix/MemoryStore.java index f102056516..f3cb430ad4 100644 --- a/quickfixj-core/src/main/java/quickfix/MemoryStore.java +++ b/quickfixj-core/src/main/java/quickfix/MemoryStore.java @@ -70,6 +70,10 @@ public Date getCreationTime() throws IOException { return creationTime.getTime(); } + public Calendar getCreationTimeCalendar() throws IOException { + return creationTime; + } + /* package */void setCreationTime(Calendar creationTime) { this.creationTime = creationTime; } diff --git a/quickfixj-core/src/main/java/quickfix/MessageStore.java b/quickfixj-core/src/main/java/quickfix/MessageStore.java index 8ff35aa3c9..aaa61ed43a 100644 --- a/quickfixj-core/src/main/java/quickfix/MessageStore.java +++ b/quickfixj-core/src/main/java/quickfix/MessageStore.java @@ -19,6 +19,7 @@ package quickfix; +import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.io.IOException; @@ -73,6 +74,14 @@ public interface MessageStore { */ Date getCreationTime() throws IOException; + /** + * Get the session creation time as a calendar object. + * + * @return the session creation time. + * @throws IOException IO error + */ + Calendar getCreationTimeCalendar() throws IOException; + /** * Reset the message store. Sequence numbers are set back to 1 and stored * messages are erased. The session creation time is also set to the time of diff --git a/quickfixj-core/src/main/java/quickfix/NoopStore.java b/quickfixj-core/src/main/java/quickfix/NoopStore.java index ddc33b54ca..8bdc4cc354 100644 --- a/quickfixj-core/src/main/java/quickfix/NoopStore.java +++ b/quickfixj-core/src/main/java/quickfix/NoopStore.java @@ -20,6 +20,7 @@ package quickfix; +import java.util.Calendar; import java.util.Collection; import java.util.Date; @@ -31,6 +32,7 @@ public class NoopStore implements MessageStore { private Date creationTime = new Date(); + private Calendar creationTimeCalendar = SystemTime.getUtcCalendar(creationTime); private int nextSenderMsgSeqNum = 1; private int nextTargetMsgSeqNum = 1; @@ -41,6 +43,10 @@ public Date getCreationTime() { return creationTime; } + public Calendar getCreationTimeCalendar() { + return creationTimeCalendar; + } + public int getNextSenderMsgSeqNum() { return nextSenderMsgSeqNum; } diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index 897cc9bdf5..8fa06c3379 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -584,7 +584,7 @@ public String getRemoteAddress() { private boolean isCurrentSession(final long time) throws IOException { return sessionSchedule == null || sessionSchedule.isSameSession( - SystemTime.getUtcCalendar(time), SystemTime.getUtcCalendar(state.getCreationTime())); + SystemTime.getUtcCalendar(time), state.getCreationTimeCalendar()); } /** diff --git a/quickfixj-core/src/main/java/quickfix/SessionState.java b/quickfixj-core/src/main/java/quickfix/SessionState.java index ef666c8520..653021d71c 100644 --- a/quickfixj-core/src/main/java/quickfix/SessionState.java +++ b/quickfixj-core/src/main/java/quickfix/SessionState.java @@ -20,10 +20,7 @@ package quickfix; import java.io.IOException; -import java.util.Collection; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -502,6 +499,10 @@ public Object getLock() { return lock; } + public Calendar getCreationTimeCalendar() throws IOException { + return messageStore.getCreationTimeCalendar(); + } + private final static class NullLog implements Log { public void onOutgoing(String message) { } diff --git a/quickfixj-core/src/main/java/quickfix/SleepycatStore.java b/quickfixj-core/src/main/java/quickfix/SleepycatStore.java index e9e7aae1c2..3fddd79f54 100644 --- a/quickfixj-core/src/main/java/quickfix/SleepycatStore.java +++ b/quickfixj-core/src/main/java/quickfix/SleepycatStore.java @@ -256,10 +256,23 @@ private void convertToIOExceptionAndRethrow(Exception e) throws IOException { throw ioe; } + + /* + * (non-Javadoc) + * @see quickfix.MessageStore#getCreationTime() + */ public Date getCreationTime() throws IOException { return info.getCreationTime().getTime(); } + /* + * (non-Javadoc) + * @see quickfix.MessageStore#getCreationTimeCalendar() + */ + public Calendar getCreationTimeCalendar() throws IOException { + return info.getCreationTime(); + } + public int getNextSenderMsgSeqNum() throws IOException { return info.getNextSenderMsgSeqNum(); } diff --git a/quickfixj-core/src/test/java/quickfix/DefaultSessionScheduleTest.java b/quickfixj-core/src/test/java/quickfix/DefaultSessionScheduleTest.java new file mode 100644 index 0000000000..7ae6919656 --- /dev/null +++ b/quickfixj-core/src/test/java/quickfix/DefaultSessionScheduleTest.java @@ -0,0 +1,120 @@ +package quickfix; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.ByteArrayInputStream; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +public class DefaultSessionScheduleTest { + + private SessionID sessionID; + @Mock + private SystemTimeSource mockTimeSource; + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + + sessionID = new SessionID("FIX.4.2:A->B"); + SystemTime.setTimeSource(mockTimeSource); + } + + @After + public void after() { + SystemTime.setTimeSource(null); + } + + @Test + public void isNonStopSession_returns_true_when_SETTING_NON_STOP_SESSION_Y() throws FieldConvertError, ConfigError { + String sessionSettingsString = "" + + "[DEFAULT]\n" + + "NonStopSession=Y\n" + + "\n" + + "[SESSION]\n" + + "BeginString=FIX.4.2\n" + + "SenderCompID=A\n" + + "TargetCompID=B\n"; + SessionSettings sessionSettings = new SessionSettings(new ByteArrayInputStream(sessionSettingsString.getBytes())); + DefaultSessionSchedule schedule = new DefaultSessionSchedule(sessionSettings, sessionID); + + assertTrue(schedule.isNonStopSession()); + } + + @Test + public void isNonStopSession_returns_false_when_SETTING_NON_STOP_SESSION_N() throws FieldConvertError, ConfigError { + String sessionSettingsString = "" + + "[DEFAULT]\n" + + "NonStopSession=N\n" + + "\n" + + "[SESSION]\n" + + "BeginString=FIX.4.2\n" + + "SenderCompID=A\n" + + "TargetCompID=B\n" + + "StartTime=00:00:00\n" + + "EndTime=00:00:01\n"; + SessionSettings sessionSettings = new SessionSettings(new ByteArrayInputStream(sessionSettingsString.getBytes())); + DefaultSessionSchedule schedule = new DefaultSessionSchedule(sessionSettings, sessionID); + + assertFalse(schedule.isNonStopSession()); + } + + @Test + public void isNonStopSession_returns_false_when_SETTING_NON_STOP_SESSION_not_present() throws FieldConvertError, ConfigError { + String sessionSettingsString = "" + + "[DEFAULT]\n" + + "\n" + + "[SESSION]\n" + + "BeginString=FIX.4.2\n" + + "SenderCompID=A\n" + + "TargetCompID=B\n" + + "StartTime=00:00:00\n" + + "EndTime=00:00:01\n"; + SessionSettings sessionSettings = new SessionSettings(new ByteArrayInputStream(sessionSettingsString.getBytes())); + DefaultSessionSchedule schedule = new DefaultSessionSchedule(sessionSettings, sessionID); + + assertFalse(schedule.isNonStopSession()); + } + + @Test + public void isSessionTime_returns_true_for_time_within_window() throws FieldConvertError, ConfigError { + when(mockTimeSource.getTime()).thenReturn(1L); + String sessionSettingsString = "" + + "[DEFAULT]\n" + + "\n" + + "[SESSION]\n" + + "BeginString=FIX.4.2\n" + + "SenderCompID=A\n" + + "TargetCompID=B\n" + + "StartTime=00:00:00\n" + + "EndTime=00:00:01\n"; + SessionSettings sessionSettings = new SessionSettings(new ByteArrayInputStream(sessionSettingsString.getBytes())); + DefaultSessionSchedule schedule = new DefaultSessionSchedule(sessionSettings, sessionID); + + assertTrue(schedule.isSessionTime()); + } + + @Test + public void isSessionTime_returns_false_for_time_outside_window() throws FieldConvertError, ConfigError { + when(mockTimeSource.getTime()).thenReturn(2000L); + String sessionSettingsString = "" + + "[DEFAULT]\n" + + "\n" + + "[SESSION]\n" + + "BeginString=FIX.4.2\n" + + "SenderCompID=A\n" + + "TargetCompID=B\n" + + "StartTime=00:00:00\n" + + "EndTime=00:00:01\n"; + SessionSettings sessionSettings = new SessionSettings(new ByteArrayInputStream(sessionSettingsString.getBytes())); + DefaultSessionSchedule schedule = new DefaultSessionSchedule(sessionSettings, sessionID); + + assertFalse(schedule.isSessionTime()); + } +} diff --git a/quickfixj-core/src/test/java/quickfix/LogUtilTest.java b/quickfixj-core/src/test/java/quickfix/LogUtilTest.java index f533c7c042..f6b5af42e4 100644 --- a/quickfixj-core/src/test/java/quickfix/LogUtilTest.java +++ b/quickfixj-core/src/test/java/quickfix/LogUtilTest.java @@ -22,6 +22,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.util.Calendar; import java.util.Date; import org.junit.After; import static org.junit.Assert.assertTrue; @@ -60,7 +61,7 @@ private void createSessionAndGenerateException(LogFactory mockLogFactory) throws Session session = new Session(null, sessionID1 -> { try { return new MemoryStore() { - public Date getCreationTime() throws IOException { + public Calendar getCreationTimeCalendar() throws IOException { throw new IOException("test"); } }; From 6edbc0bdb504a5c509212d3e1e9abbf48190b53c Mon Sep 17 00:00:00 2001 From: Philip Whitehouse Date: Tue, 28 Apr 2020 10:29:28 +0100 Subject: [PATCH 2/4] Fix imports --- quickfixj-core/src/main/java/quickfix/SessionState.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/SessionState.java b/quickfixj-core/src/main/java/quickfix/SessionState.java index 653021d71c..6d894e7b75 100644 --- a/quickfixj-core/src/main/java/quickfix/SessionState.java +++ b/quickfixj-core/src/main/java/quickfix/SessionState.java @@ -20,7 +20,11 @@ package quickfix; import java.io.IOException; -import java.util.*; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; From 6f20a92a8ce7179f96cf55275b9cfe57e809a28a Mon Sep 17 00:00:00 2001 From: Philip Whitehouse Date: Tue, 28 Apr 2020 11:15:40 +0100 Subject: [PATCH 3/4] Add CheckStyle --- checkstyle.xml | 313 +++++++++++++++++++++++++++++++++++++++++++++++++ pom.xml | 44 +++++++ 2 files changed, 357 insertions(+) create mode 100644 checkstyle.xml diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 0000000000..5a7f8d5526 --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 470c2c5f98..afc870d1a6 100644 --- a/pom.xml +++ b/pom.xml @@ -85,13 +85,37 @@ 3.5.1 1.6 2.8.2 + 3.1.1 1.6.8 3.0.0 + 8.32 + + org.apache.maven.plugins + maven-checkstyle-plugin + ${maven-checkstyle-plugin-version} + + + com.puppycrawl.tools + checkstyle + ${checkstyle-version} + + + + checkstyle.xml + + + + + check + + + + org.apache.maven.plugins maven-deploy-plugin @@ -293,6 +317,26 @@ + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${maven-checkstyle-plugin-version} + + + com.puppycrawl.tools + checkstyle + ${checkstyle-version} + + + + checkstyle.xml + + + + + ossrh From f93e84df3dadac8a5d585c7818a31aba9aed4a68 Mon Sep 17 00:00:00 2001 From: Christoph John Date: Tue, 28 Apr 2020 14:52:51 +0200 Subject: [PATCH 4/4] commented unsupported tags --- pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pom.xml b/pom.xml index afc870d1a6..90e06a0793 100644 --- a/pom.xml +++ b/pom.xml @@ -323,6 +323,7 @@ org.apache.maven.plugins maven-checkstyle-plugin ${maven-checkstyle-plugin-version} +