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);      
+  }
+
+  
 }


Reply via email to