Author: schor
Date: Wed Jul 25 18:25:11 2018
New Revision: 1836658
URL: http://svn.apache.org/viewvc?rev=1836658&view=rev
Log:
[UIMA-5842] add basic support for read-only and no-access except for 1 thread
to CAS. Still need to insert tests into all places where access should be
controlled.
Modified:
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasState.java
Modified:
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
URL:
http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java?rev=1836658&r1=1836657&r2=1836658&view=diff
==============================================================================
---
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
(original)
+++
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
Wed Jul 25 18:25:11 2018
@@ -28,6 +28,11 @@ import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MutableCallSite;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -555,8 +560,77 @@ public class CASImpl extends AbstractCas
*/
private boolean isId2Fs;
+ /***********************************
+ * C A S S T A T E management *
+ ***********************************/
private final EnumSet<CasState> casState = EnumSet.noneOf(CasState.class);
+ private static final MethodType noArgBoolean =
MethodType.methodType(boolean.class);
+ private static final MethodHandle mh_return_false;
+ private static final MethodHandle mh_return_true;
+ static {try {
+ mh_return_false = MethodHandles.lookup().findStatic(CasState.class,
"return_false", noArgBoolean);
+ mh_return_true = MethodHandles.lookup().findStatic(CasState.class,
"return_true", noArgBoolean);
+ } catch (NoSuchMethodException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } }
+
+ private final MutableCallSite is_updatable_callsite = new
MutableCallSite(mh_return_true);
+ private final MutableCallSite is_readable_callsite = new
MutableCallSite(mh_return_true);
+
+ private final MethodHandle is_updatable =
is_updatable_callsite.dynamicInvoker();
+ private final MethodHandle is_readable =
is_readable_callsite.dynamicInvoker();
+
+ private final MutableCallSite[] is_updatable_callsites = new
MutableCallSite[] {is_updatable_callsite};
+ private final MutableCallSite[] is_readable_callsites = new
MutableCallSite[] {is_readable_callsite};
+
+ private volatile Thread current_one_thread_access = null;
+
+ private void updateCallSite(MutableCallSite c, MethodHandle mh,
MutableCallSite[] cs) {
+ c.setTarget(mh);
+ MutableCallSite.syncAll(cs);
+ }
+
+ private synchronized boolean setCasState(CasState state, Thread thread) {
+ boolean wasAdded = casState.add(state);
+ if (wasAdded ||
+ (state == CasState.NO_ACCESS && thread !=
current_one_thread_access)) {
+ switch (state) {
+ case READ_ONLY:
+ if (casState.contains(CasState.NO_ACCESS)) break; // ignore
readonly if no-access is set
+ updateCallSite(is_updatable_callsite, mh_return_false,
is_updatable_callsites);
+ break;
+ case NO_ACCESS:
+ current_one_thread_access = thread;
+ MethodHandle mh = CasState.produce_one_thread_access_test(thread);
+ updateCallSite(is_updatable_callsite, mh, is_updatable_callsites);
+ updateCallSite(is_readable_callsite, mh, is_readable_callsites);
+ break;
+ default:
+ }
+ }
+ return wasAdded;
+ }
+
+ private synchronized boolean clearCasState(CasState state) {
+ boolean wasRemoved = casState.remove(state);
+ if (wasRemoved) {
+ switch (state) {
+ case READ_ONLY:
+ if (casState.contains(CasState.NO_ACCESS)) break;
+ updateCallSite(is_updatable_callsite, mh_return_true,
is_updatable_callsites);
+ break;
+ case NO_ACCESS:
+ current_one_thread_access = null;
+ updateCallSite(is_updatable_callsite, mh_return_true,
is_updatable_callsites);
+ updateCallSite(is_readable_callsite, mh_return_true,
is_readable_callsites);
+ break;
+ default:
+ }
+ }
+ return wasRemoved;
+ }
+
private SharedViewData(CASImpl baseCAS, int initialHeapSize,
TypeSystemImpl tsi) {
this.baseCAS = baseCAS;
this.tsi = tsi;
@@ -864,19 +938,25 @@ public class CASImpl extends AbstractCas
}
- /*****************************************************************
- * Non-shared instance data kept per CAS view incl base CAS
- *****************************************************************/
+ /**********************************************
+ * C A S S T A T E m a n a g e m e n t *
+ **********************************************/
- // package protected to let other things share this info
- final SharedViewData svd; // shared view data
-
/**
* @param state to add to the set
* @return true if the set changed as a result of this operation
*/
public boolean setCasState(CasState state) {
- return svd.casState.add(state);
+ return setCasState(state, null);
+ }
+
+ /**
+ * @param state to add to the set
+ * @thread null or the thread to permit access to
+ * @return true if the set changed as a result of this operation
+ */
+ public boolean setCasState(CasState state, Thread thread) {
+ return svd.setCasState(state, thread);
}
/**
@@ -892,9 +972,31 @@ public class CASImpl extends AbstractCas
* @return true if it was present, and is now removed
*/
public boolean clearCasState(CasState state) {
- return svd.casState.remove(state);
+ return svd.clearCasState(state);
}
-
+
+ boolean is_updatable() {
+ try {
+ return (boolean) svd.is_updatable.invokeExact();
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ boolean is_readable() {
+ try {
+ return (boolean) svd.is_readable.invokeExact();
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /*****************************************************************
+ * Non-shared instance data kept per CAS view incl base CAS
+ *****************************************************************/
+ // package protected to let other things share this info
+ final SharedViewData svd; // shared view data
+
/** The index repository. Referenced by XmiCasSerializer */
FSIndexRepositoryImpl indexRepository;
Modified:
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasState.java
URL:
http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasState.java?rev=1836658&r1=1836657&r2=1836658&view=diff
==============================================================================
---
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasState.java
(original)
+++
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasState.java
Wed Jul 25 18:25:11 2018
@@ -18,12 +18,37 @@
*/
package org.apache.uima.cas.impl;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
/**
* states the CAS can be in
*/
public enum CasState {
UIMA_AS_WAIT_4_RESPONSE, // when in this state, uima-as is awaiting
response from a remote,
// any attempt "release" this cas will throw an
exception
- // READ_ONLY, // multi-threaded access for reading allowed, no
updating
- // NO_ACCESS, // no reading or writing (except by privileged
internal operations)
+ READ_ONLY, // multi-threaded access for reading allowed, no
updating
+ NO_ACCESS, // no reading or writing (except by selected thread)
+ ;
+
+ static final boolean return_false() { return false; }
+ static final boolean return_true() { return true; }
+ /**
+ * @param thread the thread which is permitted to update the CAS
+ * @return true if the thread == current thread, false otherwise to block
access
+ */
+ static final boolean isSameThread(Thread thread) { return
Thread.currentThread() == thread; }
+
+ static final MethodHandle produce_one_thread_access_test(Thread thread) {
+ MethodHandle mh;
+ try {
+ mh = MethodHandles.lookup().findStatic(CasState.class, "isSameThread",
MethodType.methodType(boolean.class, Thread.class));
+ } catch (NoSuchMethodException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ return mh.bindTo(thread);
+ }
+
+
}