mirror of
https://github.com/OpenHFT/Chronicle-Map.git
synced 2021-09-13 01:26:12 +00:00
HCOLL-400 forbid nested update and write locks inside iteration contexts; rename IterationContextInterface to IterationContext; update stage-compiler dependency
This commit is contained in:
@@ -59,7 +59,7 @@ public interface Data<V> {
|
||||
return BytesUtil.bytesEqual(source, sourceOffset, bytes(), offset(), size());
|
||||
}
|
||||
|
||||
default void writeTo(RandomDataOutput target, long targetOffset) {
|
||||
default void writeTo(RandomDataOutput target, long targetOffset) {
|
||||
target.write(targetOffset, bytes(), offset(), size());
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import net.openhft.chronicle.hash.impl.stage.hash.CheckOnEachPublicOperation;
|
||||
import net.openhft.chronicle.hash.impl.stage.query.KeySearch;
|
||||
import net.openhft.chronicle.hash.locks.InterProcessLock;
|
||||
import net.openhft.chronicle.hash.serialization.internal.MetaBytesInterop;
|
||||
import net.openhft.chronicle.map.impl.IterationContext;
|
||||
import net.openhft.lang.collection.DirectBitSet;
|
||||
import net.openhft.sg.Stage;
|
||||
import net.openhft.sg.StageRef;
|
||||
@@ -258,6 +259,7 @@ public abstract class SegmentStages implements SegmentLock, LocksInterface {
|
||||
} else {
|
||||
closeNestedLocks();
|
||||
}
|
||||
deregisterIterationContextLockedInThisThread();
|
||||
localLockState = null;
|
||||
rootContextOnThisSegment = null;
|
||||
}
|
||||
@@ -379,9 +381,36 @@ public abstract class SegmentStages implements SegmentLock, LocksInterface {
|
||||
|
||||
@Stage("Locks")
|
||||
public void setLocalLockState(LocalLockState newState) {
|
||||
boolean isLocked = localLockState != UNLOCKED && localLockState != null;
|
||||
boolean goingToLock = newState != UNLOCKED && newState != null;
|
||||
if (isLocked) {
|
||||
if (!goingToLock)
|
||||
deregisterIterationContextLockedInThisThread();
|
||||
} else if (goingToLock) {
|
||||
registerIterationContextLockedInThisThread();
|
||||
}
|
||||
localLockState = newState;
|
||||
}
|
||||
|
||||
public void checkIterationContextNotLockedInThisThread() {
|
||||
if (chaining.rootContextInThisThread.iterationContextLockedInThisThread) {
|
||||
throw new IllegalStateException("Update or Write locking is forbidden in the context" +
|
||||
"of locked iteration context");
|
||||
}
|
||||
}
|
||||
|
||||
private void registerIterationContextLockedInThisThread() {
|
||||
if (this instanceof IterationContext) {
|
||||
chaining.rootContextInThisThread.iterationContextLockedInThisThread = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void deregisterIterationContextLockedInThisThread() {
|
||||
if (this instanceof IterationContext) {
|
||||
chaining.rootContextInThisThread.iterationContextLockedInThisThread = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Stage("Locks")
|
||||
public String debugContextsAndLocks() {
|
||||
String message = "";
|
||||
|
||||
@@ -42,6 +42,7 @@ public class UpdateLock implements InterProcessLock {
|
||||
public void lock() {
|
||||
switch (s.localLockState) {
|
||||
case UNLOCKED:
|
||||
s.checkIterationContextNotLockedInThisThread();
|
||||
if (s.updateZero() && s.writeZero()) {
|
||||
if (!s.readZero())
|
||||
throw forbiddenUpdateLockWhenOuterContextReadLocked();
|
||||
@@ -85,6 +86,7 @@ public class UpdateLock implements InterProcessLock {
|
||||
public void lockInterruptibly() throws InterruptedException {
|
||||
switch (s.localLockState) {
|
||||
case UNLOCKED:
|
||||
s.checkIterationContextNotLockedInThisThread();
|
||||
if (s.updateZero() && s.writeZero()) {
|
||||
if (!s.readZero())
|
||||
throw forbiddenUpdateLockWhenOuterContextReadLocked();
|
||||
@@ -105,6 +107,7 @@ public class UpdateLock implements InterProcessLock {
|
||||
public boolean tryLock() {
|
||||
switch (s.localLockState) {
|
||||
case UNLOCKED:
|
||||
s.checkIterationContextNotLockedInThisThread();
|
||||
if (s.updateZero() && s.writeZero()) {
|
||||
if (!s.readZero())
|
||||
throw forbiddenUpdateLockWhenOuterContextReadLocked();
|
||||
@@ -133,6 +136,7 @@ public class UpdateLock implements InterProcessLock {
|
||||
public boolean tryLock(long time, @NotNull TimeUnit unit) throws InterruptedException {
|
||||
switch (s.localLockState) {
|
||||
case UNLOCKED:
|
||||
s.checkIterationContextNotLockedInThisThread();
|
||||
if (s.updateZero() && s.writeZero()) {
|
||||
if (!s.readZero())
|
||||
throw forbiddenUpdateLockWhenOuterContextReadLocked();
|
||||
|
||||
@@ -40,6 +40,7 @@ public class WriteLock implements InterProcessLock {
|
||||
public void lock() {
|
||||
switch (s.localLockState) {
|
||||
case UNLOCKED:
|
||||
s.checkIterationContextNotLockedInThisThread();
|
||||
if (s.writeZero()) {
|
||||
if (!s.updateZero()) {
|
||||
s.segmentHeader.upgradeUpdateToWriteLock(s.segmentHeaderAddress);
|
||||
@@ -89,6 +90,7 @@ public class WriteLock implements InterProcessLock {
|
||||
public void lockInterruptibly() throws InterruptedException {
|
||||
switch (s.localLockState) {
|
||||
case UNLOCKED:
|
||||
s.checkIterationContextNotLockedInThisThread();
|
||||
if (s.writeZero()) {
|
||||
if (!s.updateZero()) {
|
||||
s.segmentHeader.upgradeUpdateToWriteLockInterruptibly(
|
||||
@@ -121,6 +123,7 @@ public class WriteLock implements InterProcessLock {
|
||||
public boolean tryLock() {
|
||||
switch (s.localLockState) {
|
||||
case UNLOCKED:
|
||||
s.checkIterationContextNotLockedInThisThread();
|
||||
if (s.writeZero()) {
|
||||
if (!s.updateZero()) {
|
||||
if (s.segmentHeader.tryUpgradeUpdateToWriteLock(s.segmentHeaderAddress)) {
|
||||
@@ -175,6 +178,7 @@ public class WriteLock implements InterProcessLock {
|
||||
public boolean tryLock(long time, @NotNull TimeUnit unit) throws InterruptedException {
|
||||
switch (s.localLockState) {
|
||||
case UNLOCKED:
|
||||
s.checkIterationContextNotLockedInThisThread();
|
||||
if (s.writeZero()) {
|
||||
if (!s.updateZero()) {
|
||||
if (s.segmentHeader.tryUpgradeUpdateToWriteLock(
|
||||
|
||||
@@ -23,21 +23,24 @@ import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Staged
|
||||
public class Chaining implements ChainingInterface {
|
||||
public class Chaining extends ChainingInterface {
|
||||
|
||||
public final List<ChainingInterface> contextChain;
|
||||
public final int indexInContextChain;
|
||||
|
||||
public final ChainingInterface rootContextInThisThread;
|
||||
|
||||
public Chaining() {
|
||||
contextChain = new ArrayList<>();
|
||||
contextChain.add(this);
|
||||
indexInContextChain = 0;
|
||||
rootContextInThisThread = this;
|
||||
}
|
||||
|
||||
public Chaining(ChainingInterface root) {
|
||||
contextChain = root.getContextChain();
|
||||
public Chaining(ChainingInterface rootContextInThisThread) {
|
||||
contextChain = rootContextInThisThread.getContextChain();
|
||||
indexInContextChain = contextChain.size();
|
||||
contextChain.add(this);
|
||||
this.rootContextInThisThread = rootContextInThisThread;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,14 +19,14 @@ package net.openhft.chronicle.hash.impl.stage.hash;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface ChainingInterface {
|
||||
public abstract class ChainingInterface extends ThreadLocalState {
|
||||
|
||||
List<ChainingInterface> getContextChain();
|
||||
public abstract List<ChainingInterface> getContextChain();
|
||||
|
||||
void initUsed(boolean used);
|
||||
public abstract void initUsed(boolean used);
|
||||
|
||||
boolean usedInit();
|
||||
public abstract boolean usedInit();
|
||||
|
||||
<T extends ChainingInterface> T getContext(
|
||||
public abstract <T extends ChainingInterface> T getContext(
|
||||
Class<? extends T> contextClass, Function<ChainingInterface, T> createChaining);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2015 higherfrequencytrading.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.hash.impl.stage.hash;
|
||||
|
||||
public class ThreadLocalState {
|
||||
public boolean iterationContextLockedInThisThread;
|
||||
}
|
||||
@@ -317,7 +317,7 @@ public class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super
|
||||
return iterContext;
|
||||
}
|
||||
|
||||
public IterationContextInterface<K, V, ?> iterationContext() {
|
||||
public IterationContext<K, V, ?> iterationContext() {
|
||||
return i().getContext(CompiledMapIterationContext.class,
|
||||
ci -> new CompiledMapIterationContext<>(ci, this));
|
||||
}
|
||||
@@ -342,7 +342,7 @@ public class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super
|
||||
|
||||
@Override
|
||||
public MapSegmentContext<K, V, ?> segmentContext(int segmentIndex) {
|
||||
IterationContextInterface<K, V, ?> c = iterationContext();
|
||||
IterationContext<K, V, ?> c = iterationContext();
|
||||
c.initSegmentIndex(segmentIndex);
|
||||
return c;
|
||||
}
|
||||
|
||||
+1
-2
@@ -19,8 +19,7 @@ package net.openhft.chronicle.map.impl;
|
||||
import net.openhft.chronicle.map.MapEntry;
|
||||
import net.openhft.chronicle.map.MapSegmentContext;
|
||||
|
||||
public interface IterationContextInterface<K, V, R> extends MapEntry<K, V>,
|
||||
MapSegmentContext<K, V, R> {
|
||||
public interface IterationContext<K, V, R> extends MapEntry<K, V>, MapSegmentContext<K, V, R> {
|
||||
long pos();
|
||||
|
||||
void initSegmentIndex(int segmentIndex);
|
||||
+1
-2
@@ -16,8 +16,7 @@
|
||||
|
||||
package net.openhft.chronicle.map.impl;
|
||||
|
||||
public interface ReplicatedIterationContextInterface<K, V, R>
|
||||
extends IterationContextInterface<K, V, R> {
|
||||
public interface ReplicatedIterationContext<K, V, R> extends IterationContext<K, V, R> {
|
||||
|
||||
void readExistingEntry(long pos);
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import net.openhft.chronicle.hash.Data;
|
||||
import net.openhft.chronicle.hash.impl.stage.iter.HashSegmentIteration;
|
||||
import net.openhft.chronicle.map.MapContext;
|
||||
import net.openhft.chronicle.map.MapEntry;
|
||||
import net.openhft.chronicle.map.impl.IterationContextInterface;
|
||||
import net.openhft.chronicle.map.impl.IterationContext;
|
||||
import net.openhft.chronicle.map.impl.stage.entry.MapEntryStages;
|
||||
import net.openhft.chronicle.map.impl.stage.map.WrappedValueInstanceValueHolder;
|
||||
import net.openhft.sg.StageRef;
|
||||
@@ -29,7 +29,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@Staged
|
||||
public abstract class MapSegmentIteration<K, V, R> extends HashSegmentIteration<K, MapEntry<K, V>>
|
||||
implements MapEntry<K, V>, IterationContextInterface<K, V, R> {
|
||||
implements MapEntry<K, V>, IterationContext<K, V, R> {
|
||||
|
||||
@StageRef MapEntryStages<K, V> entry;
|
||||
@StageRef WrappedValueInstanceValueHolder<K, V, ?> wrappedValueInstanceValueHolder;
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ import net.openhft.chronicle.hash.impl.VanillaChronicleHashHolder;
|
||||
import net.openhft.chronicle.hash.replication.ReplicableEntry;
|
||||
import net.openhft.chronicle.map.MapAbsentEntry;
|
||||
import net.openhft.chronicle.map.MapEntry;
|
||||
import net.openhft.chronicle.map.impl.ReplicatedIterationContextInterface;
|
||||
import net.openhft.chronicle.map.impl.ReplicatedIterationContext;
|
||||
import net.openhft.chronicle.map.impl.stage.data.DummyValueZeroData;
|
||||
import net.openhft.chronicle.map.impl.stage.entry.ReplicatedMapEntryStages;
|
||||
import net.openhft.chronicle.map.impl.stage.replication.ReplicationUpdate;
|
||||
@@ -35,7 +35,7 @@ import java.util.function.Predicate;
|
||||
|
||||
@Staged
|
||||
public abstract class ReplicatedMapSegmentIteration<K, V, R> extends MapSegmentIteration<K, V, R>
|
||||
implements ReplicatedIterationContextInterface<K, V, R>, ReplicableEntry,
|
||||
implements ReplicatedIterationContext<K, V, R>, ReplicableEntry,
|
||||
ReplicatedHashSegmentContext<K, MapEntry<K, V>>, MapAbsentEntry<K, V> {
|
||||
|
||||
@StageRef VanillaChronicleHashHolder<?, ?, ?> hh;
|
||||
|
||||
Reference in New Issue
Block a user