From c44aae129fd07f9ce7f51f6e98da74165f3a73ef Mon Sep 17 00:00:00 2001 From: Peter Lawrey Date: Fri, 24 Oct 2014 11:23:15 +0100 Subject: [PATCH 1/3] Support read/write locking. --- .../chronicle/map/ReplicatedChronicleMap.java | 38 ++++++---- .../openhft/chronicle/map/SharedSegment.java | 8 +- .../chronicle/map/VanillaChronicleMap.java | 73 +++++++++++++------ 3 files changed, 79 insertions(+), 40 deletions(-) diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java index 0f5f3ad69..e421278c4 100644 --- a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java @@ -607,7 +607,10 @@ class ReplicatedChronicleMap, */ V acquire(ThreadLocalCopies copies, MKI metaKeyWriter, KI keyWriter, K key, V usingValue, int hash2, boolean create, long timestamp) { - lock(); + if (create) + writeLock(); + else + readLock(); try { long keySize = metaKeyWriter.size(keyWriter, key); MultiStoreBytes entry = tmpBytes; @@ -636,7 +639,10 @@ class ReplicatedChronicleMap, } } } finally { - unlock(); + if (create) + writeUnlock(); + else + readUnlock(); } } @@ -654,7 +660,7 @@ class ReplicatedChronicleMap, */ private void remoteRemove(Bytes keyBytes, int hash2, final long timestamp, final byte identifier) { - lock(); + writeLock(); try { long keySize = keyBytes.remaining(); hashLookupLiveAndDeleted.startSearch(hash2); @@ -693,7 +699,7 @@ class ReplicatedChronicleMap, LOG.debug("Segment.remoteRemove() : key=" + keyBytes.toString().trim() + " was not " + "found"); } finally { - unlock(); + writeUnlock(); } } @@ -704,7 +710,7 @@ class ReplicatedChronicleMap, private void remotePut(@NotNull final Bytes inBytes, int hash2, final byte identifier, final long timestamp, long valuePos, long valueLimit) { - lock(); + writeLock(); try { // inBytes position and limit correspond to the key final long keySize = inBytes.remaining(); @@ -784,7 +790,7 @@ class ReplicatedChronicleMap, incrementSize(); } finally { - unlock(); + writeUnlock(); } } @@ -795,7 +801,7 @@ class ReplicatedChronicleMap, V put(ThreadLocalCopies copies, MKI metaKeyWriter, KI keyWriter, K key, V value, int hash2, boolean replaceIfPresent, final byte identifier, final long timestamp) { - lock(); + writeLock(); try { IntIntMultiMap hashLookup = hashLookupLiveAndDeleted; long keySize = metaKeyWriter.size(keyWriter, key); @@ -850,7 +856,7 @@ class ReplicatedChronicleMap, notifyPut(offset, true, key, value, posFromOffset(offset)); return null; } finally { - unlock(); + writeUnlock(); } } @@ -961,7 +967,7 @@ class ReplicatedChronicleMap, K key, V expectedValue, int hash2, final long timestamp, final byte identifier) { assert identifier > 0; - lock(); + writeLock(); try { long keySize = metaKeyWriter.size(keyWriter, key); final IntIntMultiMap multiMap = hashLookupLiveAndDeleted; @@ -1015,7 +1021,7 @@ class ReplicatedChronicleMap, // key is not found return null; } finally { - unlock(); + writeUnlock(); } } @@ -1029,7 +1035,7 @@ class ReplicatedChronicleMap, */ V replace(ThreadLocalCopies copies, MKI metaKeyWriter, KI keyWriter, K key, V expectedValue, V newValue, int hash2, long timestamp) { - lock(); + writeLock(); try { long keySize = metaKeyWriter.size(keyWriter, key); hashLookupLiveOnly.startSearch(hash2); @@ -1052,7 +1058,7 @@ class ReplicatedChronicleMap, // key is not found return null; } finally { - unlock(); + writeUnlock(); } } @@ -1068,7 +1074,7 @@ class ReplicatedChronicleMap, public void dirtyEntries(final long timeStamp, final ModificationIterator.EntryModifiableCallback callback) { - this.lock(); + this.readLock(); try { final int index = Segment.this.getIndex(); hashLookupLiveAndDeleted.forEach(new IntIntMultiMap.EntryConsumer() { @@ -1088,7 +1094,7 @@ class ReplicatedChronicleMap, }); } finally { - unlock(); + readUnlock(); } } @@ -1452,7 +1458,7 @@ class ReplicatedChronicleMap, this.position = position; final SharedSegment segment = segment((int) (position >>> segmentIndexShift)); - segment.lock(); + segment.readLock(); try { if (changes.clearIfSet(position)) { @@ -1473,7 +1479,7 @@ class ReplicatedChronicleMap, // while we were trying to obtain segment lock (for example, in onReplication()), // go to pick up next (next iteration in while (true) loop) } finally { - segment.unlock(); + segment.readUnlock(); } } } diff --git a/src/main/java/net/openhft/chronicle/map/SharedSegment.java b/src/main/java/net/openhft/chronicle/map/SharedSegment.java index 03c05d430..5e87e98ef 100644 --- a/src/main/java/net/openhft/chronicle/map/SharedSegment.java +++ b/src/main/java/net/openhft/chronicle/map/SharedSegment.java @@ -26,11 +26,15 @@ import java.util.Map; */ interface SharedSegment { - void lock(); + void readLock(); + + void writeLock(); Map.Entry getEntry(long pos); - void unlock(); + void readUnlock(); + + void writeUnlock(); NativeBytes entry(long pos); diff --git a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java index e6bb3a8b1..13775f0a5 100644 --- a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java @@ -627,9 +627,9 @@ class VanillaChronicleMap, } - public void lock() throws IllegalStateException { + public void readLock() throws IllegalStateException { while (true) { - final boolean success = bytes.tryLockNanosLong(LOCK_OFFSET, lockTimeOutNS); + final boolean success = bytes.tryRWReadLock(LOCK_OFFSET, lockTimeOutNS); if (success) return; if (currentThread().isInterrupted()) { throw new IllegalStateException(new InterruptedException("Unable to obtain lock, interrupted")); @@ -640,9 +640,30 @@ class VanillaChronicleMap, } } - public void unlock() { + public void writeLock() throws IllegalStateException { + while (true) { + final boolean success = bytes.tryRWWriteLock(LOCK_OFFSET, lockTimeOutNS); + if (success) return; + if (currentThread().isInterrupted()) { + throw new IllegalStateException(new InterruptedException("Unable to obtain lock, interrupted")); + } else { + errorListener.onLockTimeout(bytes.threadIdForLockLong(LOCK_OFFSET)); + bytes.resetLockLong(LOCK_OFFSET); + } + } + } + + public void readUnlock() { try { - bytes.unlockLong(LOCK_OFFSET); + bytes.unlockRWReadLock(LOCK_OFFSET); + } catch (IllegalMonitorStateException e) { + errorListener.errorOnUnlock(e); + } + } + + public void writeUnlock() { + try { + bytes.unlockRWWriteLock(LOCK_OFFSET); } catch (IllegalMonitorStateException e) { errorListener.errorOnUnlock(e); } @@ -705,7 +726,10 @@ class VanillaChronicleMap, */ V acquire(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key, V usingValue, int hash2, boolean create) { - lock(); + if (create) + writeLock(); + else + readLock(); try { long keySize = metaKeyInterop.size(keyInterop, key); MultiStoreBytes entry = tmpBytes; @@ -732,7 +756,10 @@ class VanillaChronicleMap, } } } finally { - unlock(); + if (create) + writeUnlock(); + else + readUnlock(); } } @@ -788,7 +815,7 @@ class VanillaChronicleMap, V put(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key, V value, int hash2, boolean replaceIfPresent) { - lock(); + writeLock(); try { long keySize = metaKeyInterop.size(keyInterop, key); hashLookup.startSearch(hash2); @@ -813,7 +840,7 @@ class VanillaChronicleMap, notifyPut(offset, true, key, value, posFromOffset(offset)); return null; } finally { - unlock(); + writeUnlock(); } } @@ -980,7 +1007,7 @@ class VanillaChronicleMap, */ V remove(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key, V expectedValue, int hash2) { - lock(); + writeLock(); try { long keySize = metaKeyInterop.size(keyInterop, key); hashLookup.startSearch(hash2); @@ -1006,12 +1033,12 @@ class VanillaChronicleMap, // key is not found return null; } finally { - unlock(); + writeUnlock(); } } boolean containsKey(KI keyInterop, MKI metaKeyInterop, K key, int hash2) { - lock(); + readLock(); try { long keySize = metaKeyInterop.size(keyInterop, key); IntIntMultiMap hashLookup = containsKeyHashLookup(); @@ -1023,7 +1050,7 @@ class VanillaChronicleMap, } return false; } finally { - unlock(); + readUnlock(); } } @@ -1041,7 +1068,7 @@ class VanillaChronicleMap, */ V replace(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key, V expectedValue, V newValue, int hash2) { - lock(); + writeLock(); try { long keySize = metaKeyInterop.size(keyInterop, key); hashLookup.startSearch(hash2); @@ -1058,7 +1085,7 @@ class VanillaChronicleMap, // key is not found return null; } finally { - unlock(); + writeUnlock(); } } @@ -1199,14 +1226,14 @@ class VanillaChronicleMap, } void clear() { - lock(); + writeLock(); try { hashLookup.clear(); freeList.clear(); nextPosToSearchFrom = 0; resetSize(); } finally { - unlock(); + writeUnlock(); } } @@ -1229,7 +1256,7 @@ class VanillaChronicleMap, * Check there is no garbage in freeList. */ void checkConsistency() { - lock(); + readLock(); try { IntIntMultiMap hashLookup = checkConsistencyHashLookup(); for (int pos = 0; (pos = (int) freeList.nextSetBit(pos)) >= 0; ) { @@ -1250,7 +1277,7 @@ class VanillaChronicleMap, pos += entrySizeInBlocks; } } finally { - unlock(); + readUnlock(); } } @@ -1318,7 +1345,7 @@ class VanillaChronicleMap, throw new NoSuchElementException(); final Segment segment = segments[segIndex]; try { - segment.lock(); + segment.readLock(); if (segment.getHashLookup().getPositions().isClear(pos)) { // the pos was removed after the previous advance advance(segIndex, pos); @@ -1327,7 +1354,7 @@ class VanillaChronicleMap, advance(returnedSeg = segIndex, returnedPos = pos); return returnedEntry = segment.getEntry(pos); } finally { - segment.unlock(); + segment.readUnlock(); } } } @@ -1340,21 +1367,23 @@ class VanillaChronicleMap, final Segment segment = segments[segIndex]; final int pos = (int) returnedPos; try { - segment.lock(); + segment.writeLock(); if (segment.getHashLookup().getPositions().isClear(pos)) { // The case: // 1. iterator.next() - thread 1 // 2. map.put() which cause relocation of the key, returned in above - thread 2 // OR map.remove() which remove this key - thread 2 // 3. iterator.remove() - thread 1 + segment.writeUnlock(); // not re-entrant. VanillaChronicleMap.this.remove(returnedEntry.getKey()); + segment.writeLock(); } else { removePresent(segment, pos); } returnedSeg = -1; returnedEntry = null; } finally { - segment.unlock(); + segment.writeUnlock(); } } From ea779997cfe0b96b54abe05f19a2a4f6a84d876e Mon Sep 17 00:00:00 2001 From: Peter Lawrey Date: Fri, 24 Oct 2014 11:30:24 +0100 Subject: [PATCH 2/3] Remove

from copyright messages --- pom.xml | 4 +++- .../chronicle/common/ChronicleHash.java | 4 +++- .../chronicle/common/ChronicleHashBuilder.java | 18 ++++++++++++++++++ .../common/ChronicleHashErrorListener.java | 4 +++- .../common/ChronicleHashErrorListeners.java | 4 +++- .../chronicle/common/StatelessBuilder.java | 18 ++++++++++++++++++ .../openhft/chronicle/common/TimeProvider.java | 4 +++- .../common/exceptions/IORuntimeException.java | 18 ++++++++++++++++++ .../exceptions/TimeoutRuntimeException.java | 18 ++++++++++++++++++ .../serialization/AgileBytesMarshaller.java | 4 +++- .../common/serialization/BytesInterop.java | 4 +++- .../common/serialization/BytesReader.java | 4 +++- .../common/serialization/BytesReaders.java | 4 +++- .../common/serialization/BytesWriter.java | 4 +++- .../serialization/CopyingMetaBytesInterop.java | 4 +++- .../DelegatingMetaBytesInterop.java | 4 +++- .../DelegatingMetaBytesInteropProvider.java | 4 +++- .../chronicle/common/serialization/Hasher.java | 4 +++- .../common/serialization/MetaBytesInterop.java | 4 +++- .../common/serialization/MetaBytesWriter.java | 4 +++- .../common/serialization/MetaProvider.java | 4 +++- .../common/serialization/SizeMarshaller.java | 4 +++- .../common/serialization/SizeMarshallers.java | 4 +++- .../impl/ByteArrayMarshaller.java | 4 +++- .../serialization/impl/ByteableMarshaller.java | 4 +++- .../impl/CharArrayMarshaller.java | 4 +++- .../serialization/impl/CharSequenceReader.java | 4 +++- .../serialization/impl/CharSequenceWriter.java | 4 +++- .../serialization/impl/DoubleMarshaller.java | 4 +++- .../serialization/impl/IntegerMarshaller.java | 4 +++- .../serialization/impl/LongMarshaller.java | 4 +++- .../serialization/impl/VoidMarshaller.java | 4 +++- .../chronicle/common/threadlocal/Provider.java | 4 +++- .../common/threadlocal/StatefulCopyable.java | 4 +++- .../common/threadlocal/ThreadLocalCopies.java | 4 +++- .../map/AbstractChannelReplicator.java | 4 +++- .../net/openhft/chronicle/map/Alignment.java | 4 +++- .../openhft/chronicle/map/ChannelProvider.java | 4 +++- .../chronicle/map/ChannelProviderBuilder.java | 4 +++- .../openhft/chronicle/map/ChronicleMap.java | 4 +++- .../chronicle/map/ChronicleMapBuilder.java | 4 +++- .../chronicle/map/CloseablesManager.java | 4 +++- .../chronicle/map/ConstantValueProvider.java | 4 +++- .../chronicle/map/DefaultValueProvider.java | 4 +++- .../chronicle/map/IdentifierListener.java | 18 ++++++++++++++++++ .../openhft/chronicle/map/IntIntMultiMap.java | 4 +++- .../chronicle/map/MapEventListener.java | 4 +++- .../chronicle/map/MapEventListeners.java | 4 +++- .../openhft/chronicle/map/NodeDiscovery.java | 18 ++++++++++++++++++ .../chronicle/map/NullValueProvider.java | 4 +++- .../net/openhft/chronicle/map/Objects.java | 4 +++- .../net/openhft/chronicle/map/Replica.java | 4 +++- .../chronicle/map/ReplicatedChronicleMap.java | 4 +++- .../chronicle/map/ReplicationConfig.java | 18 ++++++++++++++++++ .../chronicle/map/SerializationBuilder.java | 4 +++- .../net/openhft/chronicle/map/Serializer.java | 18 ++++++++++++++++++ .../openhft/chronicle/map/SharedSegment.java | 4 +++- .../chronicle/map/StatelessChronicleMap.java | 18 ++++++++++++++++++ .../chronicle/map/TcpReplicationConfig.java | 4 +++- .../openhft/chronicle/map/TcpReplicator.java | 4 +++- .../chronicle/map/ThrottlingConfig.java | 4 +++- .../chronicle/map/UdpChannelReplicator.java | 4 +++- .../chronicle/map/UdpReplicationConfig.java | 4 +++- .../map/UdpReplicationConfigBean.java | 18 ++++++++++++++++++ .../openhft/chronicle/map/UdpReplicator.java | 4 +++- .../chronicle/map/VanillaChronicleMap.java | 4 +++- .../chronicle/map/VanillaIntIntMultiMap.java | 4 +++- .../map/VanillaShortShortMultiMap.java | 4 +++- .../openhft/chronicle/set/ChronicleSet.java | 18 ++++++++++++++++++ .../chronicle/set/ChronicleSetBuilder.java | 4 +++- .../net/openhft/chronicle/set/DummyValue.java | 4 +++- .../chronicle/set/DummyValueMarshaller.java | 4 +++- .../net/openhft/chronicle/set/SetFromMap.java | 4 +++- src/test/java/eg/BigData.java | 4 +++- .../chronicle/map/AcquireGetUsingMain.java | 4 +++- .../net/openhft/chronicle/map/BitUnitTest.java | 4 +++- .../net/openhft/chronicle/map/Builder.java | 4 +++- .../map/ByteableIntValueMarshaller.java | 4 +++- .../map/ByteableLongValueMarshaller.java | 4 +++- .../chronicle/map/CHMLatencyTestMain.java | 4 +++- .../openhft/chronicle/map/CHMMetaDataTest.java | 4 +++- .../net/openhft/chronicle/map/CHMTest5.java | 4 +++- .../chronicle/map/CHMTestIterator1.java | 4 +++- .../chronicle/map/ChannelReplicationTest.java | 4 +++- .../chronicle/map/ChronicleMapTest.java | 4 +++- .../chronicle/map/ConcurrentMap8Test.java | 4 +++- .../map/ConstantSizeBySampleTest.java | 4 +++- .../chronicle/map/DefaultValueTest.java | 4 +++- .../chronicle/map/EntryCountMapTest.java | 18 ++++++++++++++++++ .../net/openhft/chronicle/map/GuavaTest.java | 4 +++- .../net/openhft/chronicle/map/Histogram.java | 4 +++- .../openhft/chronicle/map/HistogramTest.java | 4 +++- .../chronicle/map/IntIntMultiMapTest.java | 4 +++- .../openhft/chronicle/map/IntValueMapTest.java | 4 +++- .../java/net/openhft/chronicle/map/Issue3.java | 18 ++++++++++++++++++ .../net/openhft/chronicle/map/Issue42.java | 4 +++- .../openhft/chronicle/map/KeySizesTest.java | 4 +++- .../map/NodeDiscoveryBroadcasterTest.java | 18 ++++++++++++++++++ .../openhft/chronicle/map/OSResizesMain.java | 4 +++- .../openhft/chronicle/map/PageLatencyMain.java | 4 +++- .../chronicle/map/PostChannelCreationTest.java | 4 +++- .../map/ProcessInstanceLimiterMain.java | 4 +++- .../map/RecursiveRefereneChMapTest.java | 4 +++- .../map/ReplicatedChronicleMapTest.java | 4 +++- .../chronicle/map/ReplicationCheckingMap.java | 4 +++- .../openhft/chronicle/map/SampleValues.java | 4 +++- .../openhft/chronicle/map/SerializerTest.java | 18 ++++++++++++++++++ .../chronicle/map/SingleMapChannelTest.java | 4 +++- .../chronicle/map/StatelessClientTest.java | 18 ++++++++++++++++++ .../map/TCPSocketReplication4WayMapTest.java | 4 +++- .../TCPSocketReplicationBootStrapTests.java | 4 +++- .../map/TCPSocketReplicationIntValueTest.java | 4 +++- .../map/TCPSocketReplicationTest.java | 4 +++- ...TCPSocketReplicationTest3VoidValueTest.java | 4 +++- .../map/TCPSocketReplicationTest3way.java | 4 +++- ...ocketReplicationTest3wayPutReturnsNull.java | 4 +++- ...TCPSocketReplicationTestPostConnection.java | 4 +++- .../chronicle/map/TestBooleanValues.java | 18 ++++++++++++++++++ .../map/TimeBasedReplicationTests.java | 4 +++- .../map/TwoMapOnDifferentServers.java | 4 +++- .../map/UDPSocketReplicationTest.java | 4 +++- .../map/example/DistributedSequenceMain.java | 18 ++++++++++++++++++ .../map/fromdocs/BondVOInterface.java | 4 +++- .../OpenJDKAndHashMapExamplesTest.java | 4 +++- .../map/fromdocs/StringEncodingExamples.java | 4 +++- .../pingpong_latency/PingPongAddLeft.java | 4 +++- .../pingpong_latency/PingPongAddRight.java | 4 +++- .../pingpong_latency/PingPongCASLeft.java | 4 +++- .../pingpong_latency/PingPongCASRight.java | 4 +++- .../pingpong_latency/PingPongLockLeft.java | 4 +++- .../pingpong_latency/PingPongLockRight.java | 4 +++- .../chronicle/map/ipc/StateMachineData.java | 4 +++- .../map/ipc/StateMachineProcessor.java | 4 +++- .../chronicle/map/ipc/StateMachineState.java | 4 +++- .../map/ipc/StateMachineTutorial.java | 4 +++- .../chronicle/map/jrs166/JSR166TestCase.java | 4 +++- .../map/jrs166/map/ChronicleMapTest.java | 4 +++- .../chronicle/map/jrs166/map/LoopHelpers.java | 4 +++- .../chronicle/map/jrs166/map/MapCheck.java | 4 +++- .../jrs166/map/StatelessChronicleMapTest.java | 4 +++- .../map/utility/ProcessInstanceLimiter.java | 4 +++- .../chronicle/set/ChronicleSetBuilderTest.java | 18 ++++++++++++++++++ .../SetForTCPSocketReplicationTest3way.java | 4 +++- .../openhft/lang/values/IntValue$$Native.java | 4 +++- .../openhft/lang/values/LongValue$$Native.java | 4 +++- 145 files changed, 720 insertions(+), 126 deletions(-) diff --git a/pom.xml b/pom.xml index 8862cc7c4..b428f1ef5 100755 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,8 @@