Author: schor Date: Wed May 6 17:45:59 2015 New Revision: 1678049 URL: http://svn.apache.org/r1678049 Log: [UIMA-4381] speed up concurrent mod checking for flat iterators
Added: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/Int2IntArrayMapFixedSize.java Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexFlat.java uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImpl.java uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/UnambiguousIteratorImpl.java uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/text/AnnotationIndex.java Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexFlat.java URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexFlat.java?rev=1678049&r1=1678048&r2=1678049&view=diff ============================================================================== --- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexFlat.java (original) +++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexFlat.java Wed May 6 17:45:59 2015 @@ -29,6 +29,7 @@ import java.util.concurrent.atomic.Atomi import org.apache.uima.cas.FSIterator; import org.apache.uima.cas.FeatureStructure; import org.apache.uima.cas.impl.FSIndexRepositoryImpl.IndexIteratorCachePair; +import org.apache.uima.internal.util.Int2IntArrayMapFixedSize; import org.apache.uima.jcas.cas.TOP; /** @@ -105,7 +106,7 @@ public class FSIndexFlat<T extends Featu * The inner class implementing the Iterator * The class can't be static - makes ref to "T" invalid ******************************************** */ - public static class FSIteratorFlat<TI extends FeatureStructure> extends FSIteratorImplBase<TI> { + public static class FSIteratorFlat<TI extends FeatureStructure> extends FSIteratorImplBase<TI> implements LowLevelIterator { /** * iterator's Feature Structure array, points to the instance * in existence when the iterator was created, from the FSIndex @@ -158,7 +159,7 @@ public class FSIndexFlat<T extends Featu throw new NoSuchElementException(); } final TI fs = ifsa[pos]; - final int typeCode = ((TypeImpl)(fs.getType())).getCode(); + final int typeCode = ((FeatureStructureImpl)fs).getTypeCode(); if (debugTypeCodeUnstable) { if ((fs instanceof TOP) && // insures jcas in use !iicp.subsumes(((TOP)fs).jcasType.casTypeCode, typeCode)) { @@ -254,62 +255,25 @@ public class FSIndexFlat<T extends Featu fsIndexFlat.idInfo()); } - // A special wrapper that is just for getAllIndexed FS - // Doesn't implement moveTo(fs) - public LowLevelIterator toLLiterator() { - return new LowLevelIterator() { - - @Override - public void moveToPrevious() { - FSIteratorFlat.this.moveToPrevious(); - } - - @Override - public void moveToNext() { - FSIteratorFlat.this.moveToNext(); - } - - @Override - public void moveToLast() { - FSIteratorFlat.this.moveToLast(); - } - - @Override - public void moveToFirst() { - FSIteratorFlat.this.moveToFirst(); - } - - @Override - public void moveTo(int fsRef) { - throw new UnsupportedOperationException(); - } - - @Override - public int ll_indexSize() { - throw new UnsupportedOperationException(); - } - - @Override - public LowLevelIndex ll_getIndex() { - throw new UnsupportedOperationException(); - } - - @Override - public int ll_get() throws NoSuchElementException { - FeatureStructureImpl fsi = (FeatureStructureImpl) FSIteratorFlat.this.get(); - return fsi.getAddress(); - } - - @Override - public boolean isValid() { - return FSIteratorFlat.this.isValid(); - } - - @Override - public Object copy() { - throw new UnsupportedOperationException(); - } - }; + // methods for low level iterator + @Override + public int ll_get() throws NoSuchElementException { + return ((FeatureStructureImpl) get()).getAddress(); + } + + @Override + public void moveTo(int fsRef) { + throw new UnsupportedOperationException(); + } + + @Override + public int ll_indexSize() { + return ifsa.length; + } + + @Override + public LowLevelIndex ll_getIndex() { + throw new UnsupportedOperationException(); } } @@ -317,7 +281,7 @@ public class FSIndexFlat<T extends Featu * A reference to the non-flat shared index iterator cache pair */ private final IndexIteratorCachePair<T> iicp; - + /** * The flattened version of the above, or null * set under fsaLock @@ -352,7 +316,7 @@ public class FSIndexFlat<T extends Featu * These are read on multiple threads to determine if a * flattened iterator is still valid. */ - final int[] indexUpdateCountsResetValues; + final Int2IntArrayMapFixedSize indexUpdateCountsResetValues; /** * a map from type codes to offsets in indexUpdateCountsResetValues @@ -386,12 +350,8 @@ public class FSIndexFlat<T extends Featu */ public FSIndexFlat(IndexIteratorCachePair<T> iicp) { this.iicp = iicp; + indexUpdateCountsResetValues = iicp.createIndexUpdateCountsAtReset(); -// offset_indexUpdateCountsAtReset = new Int2IntHashMap(iicp.typeCodes.length); -// int i = 0; -// for (int typeCode : iicp.typeCodes) { -// offset_indexUpdateCountsAtReset.put(typeCode, i++); -// } debugTypeCode = iicp.getFsLeafIndex().getTypeCode(); casResetCount = iicp.getCASImpl().getCasResets(); casId = iicp.getCASImpl().getCasId(); @@ -524,7 +484,7 @@ public class FSIndexFlat<T extends Featu System.out.println(String.format("Detected cas reset while iterating in %s", idInfo())); return null; } - int topCode = iicp.typeCodes[0]; + int topCode = iicp.getFsLeafIndex().getTypeCode(); String m; if (topCode != debugTypeCode || topCode != iicp.getFsLeafIndex().getTypeCode()) { m = String.format("TypeCodesWrong: iicp[0]: %d, original=%d, leafindex=%d%n", @@ -570,7 +530,7 @@ public class FSIndexFlat<T extends Featu void captureIndexUpdateCounts() { iteratorReorderingCount = 0; - iicp.captureIndexUpdateCounts(indexUpdateCountsResetValues); + iicp.captureIndexUpdateCounts(); if (trace || smalltrace) { casResetCount = iicp.getCASImpl().getCasResets(); } Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java?rev=1678049&r1=1678048&r2=1678049&view=diff ============================================================================== --- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java (original) +++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java Wed May 6 17:45:59 2015 @@ -20,6 +20,7 @@ package org.apache.uima.cas.impl; import java.util.ArrayList; +import java.util.Arrays; import java.util.BitSet; import java.util.Collections; import java.util.Comparator; @@ -48,6 +49,7 @@ import org.apache.uima.cas.admin.LinearT import org.apache.uima.cas.impl.FSIndexFlat.FSIteratorFlat; import org.apache.uima.cas.text.AnnotationFS; import org.apache.uima.internal.util.ComparableIntPointerIterator; +import org.apache.uima.internal.util.Int2IntArrayMapFixedSize; import org.apache.uima.internal.util.IntComparator; import org.apache.uima.internal.util.IntPointerIterator; import org.apache.uima.internal.util.IntVector; @@ -225,7 +227,7 @@ public class FSIndexRepositoryImpl imple /** * The type codes corresponding to the cachedSubFsLeafIndexes, set up lazily */ - int[] typeCodes; + int[] sortedTypeCodes; @Override public String toString() { @@ -306,7 +308,7 @@ public class FSIndexRepositoryImpl imple final ArrayList<FSLeafIndexImpl<? extends T>> tempSubIndexCache = new ArrayList<FSLeafIndexImpl<? extends T>>(); final int len = allTypes.size(); if (indexKind == FSIndex.SORTED_INDEX) { - typeCodes = new int[len]; + sortedTypeCodes = new int[len]; } for (int i = 0; i < len; i++) { @@ -320,11 +322,12 @@ public class FSIndexRepositoryImpl imple throw new RuntimeException("never happen"); } if (indexKind == FSIndex.SORTED_INDEX) { - typeCodes[i] = leafIndex.getTypeCode(); + sortedTypeCodes[i] = leafIndex.getTypeCode(); } } this.cachedSubFsLeafIndexes = tempSubIndexCache; if (this.fsLeafIndex.getIndexingStrategy() == FSIndex.SORTED_INDEX) { + Arrays.sort(sortedTypeCodes); this.flatIndex = new FSIndexFlat<>(this); // must follow cachedSubFsLeafIndexes setup } // assign to "volatile" at end, after all initialization is complete @@ -434,27 +437,28 @@ public class FSIndexRepositoryImpl imple } } - int[] createIndexUpdateCountsAtReset() { - final int ni = cachedSubFsLeafIndexes.size(); - int [] ia = new int[ni]; - for (int i = 0; i < ni; i++) { - ia[i] = detectIllegalIndexUpdates[typeCodes[i]]; - } - return ia; + Int2IntArrayMapFixedSize createIndexUpdateCountsAtReset() { + Int2IntArrayMapFixedSize m = new Int2IntArrayMapFixedSize(sortedTypeCodes.length); + captureIndexUpdateCounts(m); + return m; } - void captureIndexUpdateCounts(int [] ia) { - final int ni = ia.length; - for (int i = 0; i < ni; i++) { - ia[i] = detectIllegalIndexUpdates[typeCodes[i]]; - } + void captureIndexUpdateCounts() { + captureIndexUpdateCounts(this.flatIndex.indexUpdateCountsResetValues); + } + + private void captureIndexUpdateCounts(Int2IntArrayMapFixedSize m) { + final int[] localSortedTypeCodes = sortedTypeCodes; + for (int i = 0; i < localSortedTypeCodes.length; i++) { + m.putAtIndex(i, detectIllegalIndexUpdates[localSortedTypeCodes[i]]); + } } boolean isUpdateFreeSinceLastCounterReset() { - final int[] ia = flatIndex.indexUpdateCountsResetValues; - final int ni = ia.length; - for (int i = 0; i < ni; i++) { - if (ia[i] != detectIllegalIndexUpdates[typeCodes[i]]) { + final Int2IntArrayMapFixedSize typeCode2updateCount = this.flatIndex.indexUpdateCountsResetValues; + final int[] localSortedTypeCodes = sortedTypeCodes; + for (int i = 0; i < localSortedTypeCodes.length; i++) { + if (typeCode2updateCount.getAtIndex(i) != detectIllegalIndexUpdates[localSortedTypeCodes[i]]) { return false; } } @@ -462,21 +466,10 @@ public class FSIndexRepositoryImpl imple } boolean isUpdateFreeSinceLastCounterReset(final int typeCode) { - final int[] ia = flatIndex.indexUpdateCountsResetValues; - final int ni = ia.length; - for (int i = 0; i < ni; i++) { - final int localTypeCode = typeCodes[i]; - if (typeCode != localTypeCode) { - continue; - } - if (ia[i] != detectIllegalIndexUpdates[localTypeCode]) { - return false; - } - break; // just checking one typecode, and found it; no need to check others - } - return true; + return this.flatIndex.indexUpdateCountsResetValues.get(typeCode, sortedTypeCodes) == + detectIllegalIndexUpdates[typeCode]; } - + boolean subsumes(int superType, int subType) { return cas.getTypeSystemImpl().subsumes(superType, subType); } @@ -2893,7 +2886,7 @@ public class FSIndexRepositoryImpl imple if (FSIndexFlat.trace) { System.out.format("FSIndexFlattened getAllIndexedFS use: %s%n", flatIterator.toString()); } - iteratorList.add(flatIterator.toLLiterator()); + iteratorList.add(flatIterator); return; } } Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImpl.java URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImpl.java?rev=1678049&r1=1678048&r2=1678049&view=diff ============================================================================== --- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImpl.java (original) +++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImpl.java Wed May 6 17:45:59 2015 @@ -52,6 +52,10 @@ public abstract class FeatureStructureIm return this.getCASImpl().getTypeSystemImpl().ll_getTypeForCode( this.getCASImpl().getHeapValue(this.getAddress())); } + + public int getTypeCode() { + return this.getCASImpl().getHeapValue(this.getAddress()); + } public void setFeatureValue(Feature feat, FeatureStructure fs) { final int valueAddr = this.getCASImpl().ll_getFSRef(fs); Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java?rev=1678049&r1=1678048&r2=1678049&view=diff ============================================================================== --- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java (original) +++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java Wed May 6 17:45:59 2015 @@ -46,7 +46,7 @@ public class Subiterator<T extends Annot } /** - * Create a disambiguated iterator. + * Create a disambiguated iterator. No concurrent modification exception checking is done. * * @param it * The iterator to be disambiguated. @@ -71,6 +71,7 @@ public class Subiterator<T extends Annot } } + Subiterator(FSIterator<T> it, AnnotationFS annot, final boolean ambiguous, final boolean strict) { this(); if (ambiguous) { Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/UnambiguousIteratorImpl.java URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/UnambiguousIteratorImpl.java?rev=1678049&r1=1678048&r2=1678049&view=diff ============================================================================== --- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/UnambiguousIteratorImpl.java (original) +++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/UnambiguousIteratorImpl.java Wed May 6 17:45:59 2015 @@ -34,6 +34,8 @@ import org.apache.uima.cas.text.Annotati * <p> * Warning: this implementation creates a copy of the collection, so changes in the underlying * collection are not reflected by this iterator. + * </p> + * <p>This iterator does not check for concurrent modifications and doesn't throw ConcurrentModificationExceptions.</p> * * */ Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/text/AnnotationIndex.java URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/text/AnnotationIndex.java?rev=1678049&r1=1678048&r2=1678049&view=diff ============================================================================== --- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/text/AnnotationIndex.java (original) +++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/text/AnnotationIndex.java Wed May 6 17:45:59 2015 @@ -68,6 +68,9 @@ public interface AnnotationIndex<T exten * overlap the span of <code>a</code>. * </p> * + * <p>An unambiguous iterator makes a snapshot copy of the index containing just the disambiguated items, and + * iterates over that. It doesn't check for concurrent index modifications (the ambiguous iterator does check for this). + * * @param ambiguous * If set to false, iterator will be unambiguous. * @return A annotation iterator. Added: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/Int2IntArrayMapFixedSize.java URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/Int2IntArrayMapFixedSize.java?rev=1678049&view=auto ============================================================================== --- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/Int2IntArrayMapFixedSize.java (added) +++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/Int2IntArrayMapFixedSize.java Wed May 6 17:45:59 2015 @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.uima.internal.util; + +import java.util.Arrays; + +/** + * A map<int, int> + * + * based on having a key and value int array, where the keys are sorted + * + * Supports sharing a single key array with multiple value arrays + * + * Implements Map - like interface: + * keys and values are ints + * + * values can be anything except 0; 0 is the value returned by get if not found + * + * All adds must occur before any gets; then a sort must be called unless the adds are in sort order + * + * Threading: instances of this class may be accessed on multiple threads + * (different iterators may be on different threads) + */ +public class Int2IntArrayMapFixedSize { + + private final int [] values; + private final boolean isSmall; + + public Int2IntArrayMapFixedSize(int length) { + values = new int[length]; + isSmall = length <= 4; + } + + public int get(int key, final int[] sortedKeys) { + int f = isSmall ? quickFind(key, sortedKeys) : Arrays.binarySearch(sortedKeys, key); + if (f < 0) { + throw new RuntimeException(); // return 0; // not found + } + return values[f]; + } + + private int quickFind(int key, final int[] sortedKeys) { + for (int i = 0; i < sortedKeys.length; i++) { + if (key == sortedKeys[i]) { + return i; + } + } + throw new RuntimeException(); // not found + } + + public int getAtIndex(int index) { + return values[index]; + } + + public void putAtIndex(int index, int value) { + values[index] = value; + } +}