diff --git a/src/main/java/net/openhft/chronicle/map/BuildVersion.java b/src/main/java/net/openhft/chronicle/map/BuildVersion.java index 59ec7b9f9..34292116e 100644 --- a/src/main/java/net/openhft/chronicle/map/BuildVersion.java +++ b/src/main/java/net/openhft/chronicle/map/BuildVersion.java @@ -30,20 +30,28 @@ import java.io.Reader; */ class BuildVersion { + static String version = null; /** * @return version of ChronicleMap being used, or NULL if its not known */ - public static String readVersion() { + public synchronized static String readVersion() { + + if (version != null) { + return version; + } // the best way to get the version is to read it from the manifest - final String version = getVersionFromManifest(); + final String versionFromManifest = getVersionFromManifest(); - if (version != null) + if (versionFromManifest != null) { + version = versionFromManifest; return version; + } // as a fall back for development, we will read the version from the pom file - return getVersionFromPom(); + version = getVersionFromPom(); + return version; } /** diff --git a/src/main/java/net/openhft/chronicle/map/StatelessChronicleMap.java b/src/main/java/net/openhft/chronicle/map/StatelessChronicleMap.java index 09ab6cd15..075005fea 100644 --- a/src/main/java/net/openhft/chronicle/map/StatelessChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/StatelessChronicleMap.java @@ -52,7 +52,6 @@ import static net.openhft.chronicle.map.StatelessChronicleMap.EventId.*; */ class StatelessChronicleMap implements ChronicleMap, Closeable, Cloneable { - private static final String START_OF = "Attempt to write "; private static final Logger LOG = LoggerFactory.getLogger(StatelessChronicleMap.class); private static final byte STATELESS_CLIENT_IDENTIFIER = (byte) -127; @@ -114,7 +113,8 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon PUT_IF_ABSENT, REMOVE_WITH_VALUE, TO_STRING, - VERSION, + APPLICATION_VERSION, + PERSISTED_DATA_VERSION, PUT_ALL, PUT_ALL_WITHOUT_ACC, HASH_CODE, @@ -126,6 +126,7 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon // used by the enterprise version private int identifier; + @SuppressWarnings("UnusedDeclaration") void identifier(int identifier) { this.identifier = identifier; } @@ -135,8 +136,7 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon private final AtomicLong transactionID = new AtomicLong(0); StatelessChronicleMap(@NotNull final StatelessMapConfig config, - @NotNull final ChronicleMapBuilder chronicleMapBuilder) - throws IOException { + @NotNull final ChronicleMapBuilder chronicleMapBuilder) { this.config = config; @@ -171,6 +171,21 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon inBuffer = allocateDirect(128).order(ByteOrder.nativeOrder()); inBytes = new ByteBufferBytes(inBuffer.slice()); + versionCheck(); + + } + + private void versionCheck() { + + String serverVersion = serverApplicationVersion(); + String clientVersion = clientVersion(); + + if (serverVersion.equals(clientVersion)) { + LOG.warn("The Chronicle Map Server and StalessClient are on different versions, " + + "although these version are backwards compatible, we" + + " suggest that you use the same version, server=" + serverApplicationVersion() + ", " + + "client=" + clientVersion); + } } @Override @@ -272,6 +287,8 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon if (closeables != null) closeables.closeQuietly(); clientChannel = null; } + + } /** @@ -433,8 +450,19 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon } @NotNull - public String version() { - return fetchObject(String.class, VERSION); + public String serverApplicationVersion() { + return fetchObject(String.class, APPLICATION_VERSION); + } + + @NotNull + public String serverPersistedDataVersion() { + return fetchObject(String.class, PERSISTED_DATA_VERSION); + } + + @SuppressWarnings("WeakerAccess") + @NotNull + public String clientVersion() { + return BuildVersion.readVersion(); } public boolean isEmpty() { @@ -516,16 +544,6 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon return fetchObject(PUT_MAPPED, key, unaryOperator); } - /** - * estimates the size based on what been completed so far - */ - private long estimateSize(int numberOfEntries, int numberOfEntriesReadSoFar) { - assert outBytesLock.isHeldByCurrentThread(); - assert !inBytesLock.isHeldByCurrentThread(); - // we will back the size estimate on what we have so far - final double percentageComplete = (double) numberOfEntriesReadSoFar / (double) numberOfEntries; - return (long) ((double) outBytes.position() / percentageComplete); - } private Bytes resizeBufferOutBuffer(int newCapacity) { return resizeBufferOutBuffer(newCapacity, outBytes.position()); @@ -958,9 +976,9 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon try { for (; ; ) { - if (clientChannel == null) + if (clientChannel == null) { clientChannel = lazyConnect(config.timeoutMs(), config.remoteAddress()); - + } try { if (LOG.isDebugEnabled()) @@ -1196,7 +1214,7 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon long lagestEntrySoFar = 0; - long limitOfLast = 0; + private long limitOfLast = 0; private void writeBytesToSocket(long timeoutTime) throws IOException { @@ -1294,14 +1312,7 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon private ThreadLocalCopies writeKey(K key, ThreadLocalCopies copies) { assert outBytesLock.isHeldByCurrentThread(); assert !inBytesLock.isHeldByCurrentThread(); - - long start = outBytes.position(); - - for (; ; ) { - - return keyWriterWithSize.write(outBytes, key, copies); - - } + return keyWriterWithSize.write(outBytes, key, copies); } @SuppressWarnings("UnusedReturnValue") @@ -1309,8 +1320,6 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon assert outBytesLock.isHeldByCurrentThread(); assert !inBytesLock.isHeldByCurrentThread(); - - return keyWriterWithSize.writeInLoop(outBytes, key, writer, copies); } diff --git a/src/main/java/net/openhft/chronicle/map/TcpReplicator.java b/src/main/java/net/openhft/chronicle/map/TcpReplicator.java index 5a4364ef0..c9c42e15f 100644 --- a/src/main/java/net/openhft/chronicle/map/TcpReplicator.java +++ b/src/main/java/net/openhft/chronicle/map/TcpReplicator.java @@ -1489,8 +1489,11 @@ class StatelessServerConnector { case TO_STRING: return toString(writer.in(), sizeLocation); - case VERSION: - return version(writer.in(), sizeLocation); + case APPLICATION_VERSION: + return applicationVersion(writer.in(), sizeLocation); + + case PERSISTED_DATA_VERSION: + return persistedDataVersion(writer.in(), sizeLocation); case PUT_ALL: return putAll(reader, writer.in(), sizeLocation, timestamp, identifier); @@ -1615,12 +1618,31 @@ class StatelessServerConnector { @Nullable - private Work version(@NotNull Bytes writer, final long sizeLocation) { + private Work applicationVersion(@NotNull Bytes writer, final long sizeLocation) { final long remaining = writer.remaining(); try { - String result = map.version(); + String result = map.applicationVersion(); + writer.writeObject(result); + } catch (Throwable e) { + return sendException(writer, sizeLocation, e); + } + + assert remaining > 4; + + writeSizeAndFlags(sizeLocation, false, writer); + return null; + } + + + @Nullable + private Work persistedDataVersion(@NotNull Bytes writer, final long sizeLocation) { + + + final long remaining = writer.remaining(); + try { + String result = map.persistedDataVersion(); writer.writeObject(result); } catch (Throwable e) { return sendException(writer, sizeLocation, e); diff --git a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java index 957d0cd12..690d6a2ea 100755 --- a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java @@ -73,7 +73,7 @@ class VanillaChronicleMap, static final int MAX_ENTRY_OVERSIZE_FACTOR = 64; private static final long serialVersionUID = 2L; final Class kClass; - final String mapVersion; + final String dataFileVersion; final SizeMarshaller keySizeMarshaller; final BytesReader originalKeyReader; final KI originalKeyInterop; @@ -122,7 +122,7 @@ class VanillaChronicleMap, kClass = keyBuilder.eClass; keySizeMarshaller = keyBuilder.sizeMarshaller(); originalKeyReader = keyBuilder.reader(); - mapVersion = BuildVersion.readVersion(); + dataFileVersion = BuildVersion.readVersion(); originalKeyInterop = (KI) keyBuilder.interop(); @@ -178,12 +178,20 @@ class VanillaChronicleMap, } /** - * @return the version of Chronicle Map this instance was built with + * @return the version of Chronicle Map that was used to create the current data file */ - String version() { - return mapVersion; + public String persistedDataVersion() { + return dataFileVersion; } + /** + * @return the version of chronicle map that is currently running + */ + public String applicationVersion() { + return BuildVersion.readVersion(); + } + + final long segmentHash(long hash) { return hashSplitting.segmentHash(hash); } diff --git a/src/test/java/net/openhft/chronicle/map/BuildVersionTest.java b/src/test/java/net/openhft/chronicle/map/BuildVersionTest.java index 3c20c9f17..6eb8ac964 100644 --- a/src/test/java/net/openhft/chronicle/map/BuildVersionTest.java +++ b/src/test/java/net/openhft/chronicle/map/BuildVersionTest.java @@ -50,7 +50,7 @@ public class BuildVersionTest { .create()) { expected.put(1, 1.0); - String version = ((VanillaChronicleMap) expected).version(); + String version = ((VanillaChronicleMap) expected).persistedDataVersion(); Assert.assertNotNull(BuildVersion.readVersion(), version); } diff --git a/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java b/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java index 937dd5802..5280d5e14 100644 --- a/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java +++ b/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java @@ -690,7 +690,7 @@ public class StatelessClientTest { .class, StringBuilder.class) .statelessClient(new InetSocketAddress("localhost", port)).create()) { - assertTrue(!((StatelessChronicleMap) statelessMap).version().isEmpty()); + assertTrue(!((StatelessChronicleMap) statelessMap).serverApplicationVersion().isEmpty()); } } diff --git a/src/test/java/net/openhft/chronicle/map/TestOversizedReplicationHub.java b/src/test/java/net/openhft/chronicle/map/TestOversizedReplicationHub.java index 2f32ccbc2..790404c8e 100644 --- a/src/test/java/net/openhft/chronicle/map/TestOversizedReplicationHub.java +++ b/src/test/java/net/openhft/chronicle/map/TestOversizedReplicationHub.java @@ -39,7 +39,7 @@ public class TestOversizedReplicationHub { byte identifier = (byte) 1; TcpTransportAndNetworkConfig tcpConfig = TcpTransportAndNetworkConfig - .of(8086, new InetSocketAddress("localhost", 8087)) + .of(8021, new InetSocketAddress("localhost", 8022)) .heartBeatInterval(1, TimeUnit.SECONDS); ReplicationHub hubOnServer1 = ReplicationHub.builder() @@ -74,7 +74,7 @@ public class TestOversizedReplicationHub { byte identifier = (byte) 2; TcpTransportAndNetworkConfig tcpConfig = TcpTransportAndNetworkConfig - .of(8087).heartBeatInterval(1, TimeUnit.SECONDS); + .of(8022).heartBeatInterval(1, TimeUnit.SECONDS); ReplicationHub hubOnServer2 = ReplicationHub.builder() .tcpTransportAndNetwork(tcpConfig)