HCOLL-400 forbid nested update and write locks inside iteration contexts; rename IterationContextInterface to IterationContext; update stage-compiler dependency

This commit is contained in:
leventov
2015-10-09 15:09:32 +03:00
parent b02d738cf2
commit cad3d3abfe
14 changed files with 253 additions and 21 deletions
@@ -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;
}
@@ -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);
@@ -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;
@@ -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;