You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2013/11/01 01:53:32 UTC

svn commit: r1537789 - in /uima/uimaj/trunk/uimaj-core/src: main/java/org/apache/uima/cas/impl/ main/java/org/apache/uima/internal/util/ test/java/org/apache/uima/cas/impl/ test/java/org/apache/uima/internal/util/

Author: schor
Date: Fri Nov  1 00:53:32 2013
New Revision: 1537789

URL: http://svn.apache.org/r1537789
Log:
[UIMA-3396] Also do speedup of getAllIndexes using sorting (once) and de-duping; add sortDedup to IntVector, and test cases for this and for 3396.

Added:
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java.svntmp
    uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/internal/util/IntVectorTest.java
Modified:
    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/internal/util/IntVector.java
    uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCasDeserializerTest.java

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=1537789&r1=1537788&r2=1537789&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 Fri Nov  1 00:53:32 2013
@@ -1471,9 +1471,13 @@ public class FSIndexRepositoryImpl imple
   // Serialization support
 
   /**
-   * Return an array containing all FSs in any index. This is intended to be used for serialization.
-   * Note that duplicate entries in indexes will appear in the array as many times as they occur in
-   * an index. The order in which FSs occur in the array does not reflect the order in which they
+   * For one particular view (the one associated with this instance of FsIndexRepositoryImpl),
+   * return an array containing all FSs in any defined index, in this view. 
+   * This is intended to be used for serialization.
+   * 
+   * Note that duplicate entries are removed, and the results are sorted by FS address.
+   * 
+   * The order in which FSs occur in the array does not reflect the order in which they
    * were added to the repository. This means that set indexes deserialized from this list may
    * contain different but equal elements than the original index.
    */
@@ -1484,9 +1488,9 @@ public class FSIndexRepositoryImpl imple
     ArrayList<IndexIteratorCachePair> iv, cv;
     // We may need to profile this. If this is a bottleneck, use a different
     // implementation.
-    SortedIntSet set;
+    IntVector indexedFSs = new IntVector();
     int jMax, indStrat;
-    // Iterate over indexes with something in there
+    // Iterate over index by type, with something in there
     for (int i = 0; i < this.usedIndexes.size(); i++) {
       iv = this.indexArray[this.usedIndexes.get(i)];
       // Iterate over the indexes for the type.
@@ -1515,15 +1519,17 @@ public class FSIndexRepositoryImpl imple
         // Duplicates arise from having mulitple sets combined, and
         // also if a non-set index had the same identical FS added
         // multiple times.
-        set = new SortedIntSet();
+        indexedFSs.removeAllElements();
         for (int k = 0; k < cv.size(); k++) {
           it = cv.get(k).index.refIterator();
           while (it.isValid()) {
-            set.add(it.get());
+            indexedFSs.add(it.get());
             it.inc();
           }
         }
-        v.add(set.getArray(), 0, set.size());  // bulk add of all elements
+        // sort and remove duplicates
+        indexedFSs.sortDedup();
+        v.add(indexedFSs.getArray(), 0, indexedFSs.size());  // bulk add of all elements
 //        for (int k = 0; k < set.size(); k++) {
 //          v.add(set.get(k));
 //        }
@@ -1738,28 +1744,59 @@ public class FSIndexRepositoryImpl imple
   }
 
   // Delta Serialization support
+  /**
+   * Go through the journal, and use those entries to update
+   *   added, deleted, and reindexed lists
+   * in such a way as to guarantee:
+   *   a FS is in only one of these lists, (or in none)
+   *   
+   * For a journal "add-to-indexes" event:
+   *   fs in "deleted":  remove from "deleted", add to "reindexed"
+   *   fs in "reindexed": do nothing
+   *   fs in "added": do nothing
+   *   fs not in any of these: add to "added"
+   *   
+   * For a journal "remove-from-indexes" event:
+   *   fs in "added": remove from "added" (don't add to "deleted")
+   *   fs in "reindexed": remove from "reindexed" and add to "deleted")
+   *   fs in "deleted": do nothing
+   *   fs not in any of these: add to "deleted"
+   *   
+   * The journal is cleared after processing.
+   */
   private void processIndexUpdates() {
     for (int i = 0; i < this.indexUpdates.size(); i++) {
       final int fsRef = this.indexUpdates.get(i);
       final boolean added = this.indexUpdateOperation.get(i);
       if (added) {
-        if (this.fsDeletedFromIndex.contains(fsRef)) {
-          this.fsDeletedFromIndex.remove(this.fsDeletedFromIndex.indexOf(fsRef));
+        final int indexOfDeletedItem = this.fsDeletedFromIndex.indexOf(fsRef);
+        if (indexOfDeletedItem >= 0) {
+          this.fsDeletedFromIndex.remove(indexOfDeletedItem);
           this.fsReindexed.add(fsRef);
+        } else if (this.fsReindexed.contains(fsRef)) {
+          continue;  // skip adding this to anything
         } else {
-          this.fsAddedToIndex.add(fsRef);
+          this.fsAddedToIndex.add(fsRef);  // this is a set, so dups not added
         }
       } else {
-        if (this.fsAddedToIndex.contains(fsRef)) {
-          this.fsAddedToIndex.remove(this.fsAddedToIndex.indexOf(fsRef));
-        } else if (this.fsReindexed.contains(fsRef)) {
-          this.fsReindexed.remove(fsRef);
+        final int indexOfaddedItem = this.fsAddedToIndex.indexOf(fsRef);
+        if (indexOfaddedItem >= 0) {
+          this.fsAddedToIndex.remove(indexOfaddedItem);
         } else {
-          this.fsDeletedFromIndex.add(fsRef);
+          final int indexOfReindexedItem = this.fsReindexed.indexOf(fsRef);
+          if (indexOfReindexedItem >= 0) {
+            this.fsReindexed.remove(indexOfReindexedItem);
+            this.fsDeletedFromIndex.add(fsRef);
+          }
+          else {
+            this.fsDeletedFromIndex.add(fsRef);
+          }
         }
       }
     }
     this.logProcessed = true;
+    this.indexUpdates.removeAllElements();
+    this.indexUpdateOperation.clear();
   }
 
   public int[] getAddedFSs() {

Added: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java.svntmp
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java.svntmp?rev=1537789&view=auto
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java.svntmp (added)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java.svntmp Fri Nov  1 00:53:32 2013
@@ -0,0 +1,1842 @@
+/*
+ * 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.cas.impl;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.CASException;
+import org.apache.uima.cas.CASRuntimeException;
+import org.apache.uima.cas.FSIndex;
+import org.apache.uima.cas.FSIterator;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.cas.admin.CASAdminException;
+import org.apache.uima.cas.admin.FSIndexComparator;
+import org.apache.uima.cas.admin.FSIndexRepositoryMgr;
+import org.apache.uima.cas.admin.LinearTypeOrder;
+import org.apache.uima.cas.admin.LinearTypeOrderBuilder;
+import org.apache.uima.internal.util.ComparableIntPointerIterator;
+import org.apache.uima.internal.util.IntComparator;
+import org.apache.uima.internal.util.IntPointerIterator;
+import org.apache.uima.internal.util.IntSet;
+import org.apache.uima.internal.util.IntVector;
+import org.apache.uima.internal.util.SortedIntSet;
+
+public class FSIndexRepositoryImpl implements FSIndexRepositoryMgr, LowLevelIndexRepository {
+
+  // Implementation note: the use of equals() here is pretty hairy and
+  // should probably be fixed. We rely on the fact that when two
+  // FSIndexComparators are compared, the type of the comparators is
+  // ignored! A fix for this would be to split the FSIndexComparator
+  // class into two classes, one for the key-comparator pairs, and one
+  // for the combination of the two. Note also that we compare two
+  // IndexIteratorCachePairs by comparing their
+  // index.getComparator()s.
+
+  /**
+   * A pair of an index and an iterator cache. An iterator cache is the set of all indexes necessary
+   * to create an iterator for the type of the index. compareTo() is based on types and the
+   * comparator of the index.
+   */
+  private class IndexIteratorCachePair implements Comparable<IndexIteratorCachePair> {
+
+    // The "root" index, i.e., index of the type of the iterator.
+    private FSLeafIndexImpl<?> index = null;
+
+    // A list of indexes (the sub-indexes that we need for an
+    // iterator). I.e., one index for each type that's subsumed by the
+    // iterator
+    // type.
+    private ArrayList<FSLeafIndexImpl<?>> iteratorCache = null;
+
+    private IndexIteratorCachePair() {
+      super();
+    }
+
+    // Two IICPs are equal iff their index comparators are equal AND their
+    // indexing strategy is the same.
+    @Override
+    public boolean equals(Object o) {
+      if (!(o instanceof IndexIteratorCachePair)) {
+        return false;
+      }
+      final IndexIteratorCachePair iicp = (IndexIteratorCachePair) o;
+      return this.index.getComparator().equals(iicp.index.getComparator())
+          && (this.index.getIndexingStrategy() == iicp.index.getIndexingStrategy());
+    }
+
+    @Override
+    public int hashCode() {
+      throw new UnsupportedOperationException();
+    }
+
+    // Populate the cache.
+    private void createIndexIteratorCache() {
+      if (this.iteratorCache != null) {
+        return;
+      }
+      this.iteratorCache = new ArrayList<FSLeafIndexImpl<?>>();
+      final Type rootType = this.index.getComparator().getType();
+      ArrayList<Type> allTypes = null;
+      if (this.index.getIndexingStrategy() == FSIndex.DEFAULT_BAG_INDEX) {
+        allTypes = new ArrayList<Type>();
+        allTypes.add(rootType);
+      } else {
+        allTypes = getAllSubsumedTypes(rootType, FSIndexRepositoryImpl.this.typeSystem);
+      }
+      final int len = allTypes.size();
+      int typeCode, indexPos;
+      ArrayList<IndexIteratorCachePair> indexList;
+      for (int i = 0; i < len; i++) {
+        typeCode = ((TypeImpl) allTypes.get(i)).getCode();
+        indexList = FSIndexRepositoryImpl.this.indexArray[typeCode];
+        indexPos = indexList.indexOf(this);
+        if (indexPos >= 0) {
+          this.iteratorCache.add(indexList.get(indexPos).index);
+        }
+      }
+    }
+
+    /**
+     * @see java.lang.Comparable#compareTo(Object)
+     */
+    public int compareTo(IndexIteratorCachePair o) {
+      final IndexIteratorCachePair cp = o;
+      final int typeCode1 = ((TypeImpl) this.index.getType()).getCode();
+      final int typeCode2 = ((TypeImpl) cp.index.getType()).getCode();
+      if (typeCode1 < typeCode2) {
+        return -1;
+      } else if (typeCode1 > typeCode2) {
+        return 1;
+      } else { // types are equal
+        return this.index.getComparator().compareTo(cp.index.getComparator());
+      }
+    }
+
+    int size() {
+      int size = 0;
+      for (int i = 0; i < this.iteratorCache.size(); i++) {
+        size += this.iteratorCache.get(i).size();
+      }
+      return size;
+    }
+
+  }
+
+  IntPointerIterator createPointerIterator(IndexIteratorCachePair iicp) {
+    iicp.createIndexIteratorCache();
+    if (iicp.iteratorCache.size() > 1) {
+      return new PointerIterator(iicp);
+    }
+    return new LeafPointerIterator(iicp);
+  }
+
+  IntPointerIterator createPointerIterator(IndexIteratorCachePair iicp, int fs) {
+    iicp.createIndexIteratorCache();
+    if (iicp.iteratorCache.size() > 1) {
+      return new PointerIterator(iicp, fs);
+    }
+    return new LeafPointerIterator(iicp, fs);
+  }
+
+  /**
+   * The iterator implementation for indexes. Tricky because the iterator needs to be able to move
+   * backwards as well as forwards.
+   */
+  private class PointerIterator implements IntPointerIterator, LowLevelIterator {
+
+    /**
+     * The number of elements to keep in order before the binary heap starts. This section helps the
+     * performance in cases where a couple of types dominate the index.
+     */
+    static final int SORTED_SECTION = 3;
+
+    // The IICP
+    private IndexIteratorCachePair iicp;
+
+    // An array of ComparableIntPointerIterators, one for each subtype.
+    //   Each instance of these has a Class.this kind of ref to a particular variety of FSLeafIndex (bag, set, sorted) corresponding to 1 type
+    //   This array has the indexes for all the subtypes
+    private ComparableIntPointerIterator[] indexes;
+
+    int lastValidIndex;
+
+    // snapshot to detectIllegalIndexUpdates
+    // need to move this to ComparableIntPointerIterator so it can be tested
+
+    // currentIndex is always 0
+
+    // The iterator works in two modes:
+    // Forward and backward processing. This flag tells which mode we're in.
+    // The iterator heap needs to be reconstructed when we switch direction.
+    private boolean wentForward;
+
+    // Comparator that is used to compare FS addresses for the purposes of
+    // iteration.
+    private IntComparator iteratorComparator;
+
+    // The next element in the iterator. When next < 0, there is no
+    // next.
+    // private int next;
+
+    private PointerIterator() {
+      super();
+    }
+
+    private void initPointerIterator(IndexIteratorCachePair iicp0) {
+      this.iicp = iicp0;
+      // Make sure the iterator cache exists.
+      final ArrayList<FSLeafIndexImpl<?>> iteratorCache = iicp0.iteratorCache;
+      this.indexes = new ComparableIntPointerIterator[iteratorCache.size()];
+      this.iteratorComparator = iteratorCache.get(0);
+      ComparableIntPointerIterator it;
+      for (int i = 0; i < this.indexes.length; i++) {
+        final FSLeafIndexImpl<?> leafIndex = iteratorCache.get(i);
+        it = leafIndex.pointerIterator(this.iteratorComparator,
+            FSIndexRepositoryImpl.this.detectIllegalIndexUpdates,
+            ((TypeImpl) leafIndex.getType()).getCode());
+        this.indexes[i] = it;
+      }
+    }
+
+    private PointerIterator(IndexIteratorCachePair iicp) {
+      super();
+      initPointerIterator(iicp);
+      moveToFirst();
+    }
+
+    private PointerIterator(IndexIteratorCachePair iicp, int fs) {
+      super();
+      initPointerIterator(iicp);
+      moveTo(fs);
+    }
+
+    public boolean isValid() {
+      // We're valid as long as at least one index is.
+      return (this.lastValidIndex >= 0);
+    }
+
+    private ComparableIntPointerIterator checkConcurrentModification(int i) {
+      final ComparableIntPointerIterator cipi = this.indexes[i];
+      if (cipi.isConcurrentModification()) {
+        throw new ConcurrentModificationException();
+      }
+      return cipi;
+    }
+
+    /**
+     * Test the order with which the two iterators should be used. Introduces arbitrary ordering for
+     * equivalent FSs. Only called with valid iterators.
+     * 
+     * @param l
+     * @param r
+     * @param dir
+     *          Direction of movement, 1 for forward, -1 for backward
+     * @return true if the left iterator needs to be used before the right one.
+     */
+    private boolean is_before(ComparableIntPointerIterator l, ComparableIntPointerIterator r,
+        int dir) {
+      final int il = l.get();
+      final int ir = r.get();
+      int d = this.iteratorComparator.compare(il, ir);
+
+      // If two FSs are identical wrt the comparator of the index,
+      // we still need to be able to distinguish them to be able to have a
+      // well-defined sequence. In that case, we arbitrarily order FSs by
+      // their
+      // addresses. We need to do this in order to be able to ensure that a
+      // reverse iterator produces the reverse order of the forward iterator.
+      if (d == 0) {
+        d = il - ir;
+      }
+
+      return d * dir < 0;
+    }
+
+    /**
+     * Move the idx'th element up in the heap until it finds its proper position.
+     * 
+     * @param it
+     *          indexes[idx]
+     * @param idx
+     *          Element to move
+     * @param dir
+     *          Direction of iterator movement, 1 for forward, -1 for backward
+     */
+    private void heapify_up(ComparableIntPointerIterator it, int idx, int dir) {
+      int nidx;
+
+      while (idx > SORTED_SECTION) {
+        nidx = (idx + SORTED_SECTION - 1) >> 1;
+        if (!is_before(it, this.indexes[nidx], dir)) {
+          this.indexes[idx] = it;
+          return;
+        }
+        this.indexes[idx] = this.indexes[nidx];
+        idx = nidx;
+      }
+
+      while (idx > 0) {
+        nidx = idx - 1;
+        if (!is_before(it, this.indexes[nidx], dir)) {
+          this.indexes[idx] = it;
+          return;
+        }
+        this.indexes[idx] = this.indexes[nidx];
+        idx = nidx;
+      }
+
+      this.indexes[idx] = it;
+    }
+
+    /**
+     * Move the top element down in the heap until it finds its proper position.
+     * 
+     * @param it
+     *          indexes[0]
+     * @param dir
+     *          Direction of iterator movement, 1 for forward, -1 for backward
+     */
+    private void heapify_down(ComparableIntPointerIterator it, int dir) {
+      if (!it.isValid()) {
+        final ComparableIntPointerIterator itl = checkConcurrentModification(this.lastValidIndex);
+        this.indexes[this.lastValidIndex] = it;
+        this.indexes[0] = itl;
+        --this.lastValidIndex;
+        it = itl;
+      }
+
+      final int num = this.lastValidIndex;
+      if ((num < 1) || !is_before(checkConcurrentModification(1), it, dir)) {
+        return;
+      }
+
+      int idx = 1;
+      this.indexes[0] = this.indexes[1];
+      final int end = Math.min(num, SORTED_SECTION);
+      int nidx = idx + 1;
+
+      // make sure we don't leave the iterator in a completely invalid state
+      // (i.e. one it can't recover from using moveTo/moveToFirst/moveToLast)
+      // in case of a concurrent modification
+      try {
+        while (nidx <= end) {
+          if (!is_before(checkConcurrentModification(nidx), it, dir)) {
+            return; // passes through finally
+          }
+
+          this.indexes[idx] = this.indexes[nidx];
+          idx = nidx;
+          nidx = idx + 1;
+        }
+
+        nidx = SORTED_SECTION + 1;
+        while (nidx <= num) {
+          if ((nidx < num)
+              && is_before(checkConcurrentModification(nidx + 1),
+                  checkConcurrentModification(nidx), dir)) {
+            ++nidx;
+          }
+
+          if (!is_before(this.indexes[nidx], it, dir)) {
+            return;
+          }
+
+          this.indexes[idx] = this.indexes[nidx];
+          idx = nidx;
+          nidx = (nidx << 1) - (SORTED_SECTION - 1);
+        }
+      } finally {
+        this.indexes[idx] = it;
+      }
+    }
+
+    public void moveToFirst() {
+      int lvi = this.indexes.length - 1;
+      // Need to consider all iterators.
+      // Set all iterators to insertion point.
+      int i = 0;
+      while (i <= lvi) {
+        final ComparableIntPointerIterator it = this.indexes[i];
+        it.resetConcurrentModification();
+        it.moveToFirst();
+        if (it.isValid()) {
+          heapify_up(it, i, 1);
+          ++i;
+        } else {
+          // swap this iterator with the last possibly valid one
+          // lvi might be equal to i, this will not be a problem
+          this.indexes[i] = this.indexes[lvi];
+          this.indexes[lvi] = it;
+          --lvi;
+        }
+      }
+      // configured to continue with forward iterations
+      this.wentForward = true;
+      this.lastValidIndex = lvi;
+    }
+
+    public void moveToLast() {
+      int lvi = this.indexes.length - 1;
+      // Need to consider all iterators.
+      // Set all iterators to insertion point.
+      int i = 0;
+      while (i <= lvi) {
+        final ComparableIntPointerIterator it = this.indexes[i];
+        it.resetConcurrentModification();
+        it.moveToLast();
+        if (it.isValid()) {
+          heapify_up(it, i, -1);
+          ++i;
+        } else {
+          // swap this iterator with the last possibly valid one
+          // lvi might be equal to i, this will not be a problem
+          this.indexes[i] = this.indexes[lvi];
+          this.indexes[lvi] = it;
+          --lvi;
+        }
+      }
+      // configured to continue with backward iterations
+      this.wentForward = false;
+      this.lastValidIndex = lvi;
+    }
+
+    public void moveToNext() {
+      if (!isValid()) {
+        return;
+      }
+
+      final ComparableIntPointerIterator it0 = checkConcurrentModification(0);
+
+      if (this.wentForward) {
+        it0.inc();
+        heapify_down(it0, 1);
+      } else {
+        // We need to increment everything.
+        int lvi = this.indexes.length - 1;
+        int i = 1;
+        while (i <= lvi) {
+          // Any iterator other than the current one needs to be
+          // incremented until it's pointing at something that's
+          // greater than the current element.
+          final ComparableIntPointerIterator it = checkConcurrentModification(i);
+          // If the iterator we're considering is not valid, we
+          // set it to the first element. This should be it for this iterator...
+          if (!it.isValid()) {
+            it.moveToFirst();
+          }
+          // Increment the iterator while it is valid and pointing
+          // at something smaller than the current element.
+          while (it.isValid() && is_before(it, it0, 1)) {
+            it.inc();
+          }
+
+          // find placement
+          if (it.isValid()) {
+            heapify_up(it, i, 1);
+            ++i;
+          } else {
+            // swap this iterator with the last possibly valid one
+            // lvi might be equal to i, this will not be a problem
+            this.indexes[i] = this.indexes[lvi];
+            this.indexes[lvi] = it;
+            --lvi;
+          }
+        }
+
+        this.lastValidIndex = lvi;
+        this.wentForward = true;
+
+        it0.inc();
+        heapify_down(it0, 1);
+      }
+    }
+
+    public void moveToPrevious() {
+      if (!isValid()) {
+        return;
+      }
+
+      final ComparableIntPointerIterator it0 = checkConcurrentModification(0);
+      if (!this.wentForward) {
+        it0.dec();
+        // this also takes care of invalid iterators
+        heapify_down(it0, -1);
+      } else {
+        // We need to decrement everything.
+        int lvi = this.indexes.length - 1;
+        int i = 1;
+        while (i <= lvi) {
+          // Any iterator other than the current one needs to be
+          // decremented until it's pointing at something that's
+          // smaller than the current element.
+          final ComparableIntPointerIterator it = checkConcurrentModification(i);
+          // If the iterator we're considering is not valid, we
+          // set it to the last element. This should be it for this iterator...
+          if (!it.isValid()) {
+            it.moveToLast();
+          }
+          // Decrement the iterator while it is valid and pointing
+          // at something greater than the current element.
+          while (it.isValid() && is_before(it, it0, -1)) {
+            it.dec();
+          }
+
+          // find placement
+          if (it.isValid()) {
+            heapify_up(it, i, -1);
+            ++i;
+          } else {
+            // swap this iterator with the last possibly valid one
+            // lvi might be equal to i, this will not be a problem
+            this.indexes[i] = this.indexes[lvi];
+            this.indexes[lvi] = it;
+            --lvi;
+          }
+        }
+
+        this.lastValidIndex = lvi;
+        this.wentForward = false;
+
+        it0.dec();
+        heapify_down(it0, -1);
+      }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.uima.cas.impl.LowLevelIterator#ll_get()
+     */
+    public int get() throws NoSuchElementException {
+      return ll_get();
+    }
+
+    public int ll_get() {
+      if (!isValid()) {
+        throw new NoSuchElementException();
+      }
+      return checkConcurrentModification(0).get();
+    }
+
+    public Object copy() {
+      // If this.isValid(), return a copy pointing to the same element.
+      if (this.isValid()) {
+        return new PointerIterator(this.iicp, this.get());
+      }
+      // Else, create a copy that is also not valid.
+      final PointerIterator pi = new PointerIterator(this.iicp);
+      pi.moveToFirst();
+      pi.moveToPrevious();
+      return pi;
+    }
+
+    /**
+     * @see org.apache.uima.internal.util.IntPointerIterator#moveTo(int)
+     */
+    public void moveTo(int fs) {
+      int lvi = this.indexes.length - 1;
+      // Need to consider all iterators.
+      // Set all iterators to insertion point.
+      int i = 0;
+      while (i <= lvi) {
+        final ComparableIntPointerIterator it = this.indexes[i];
+        it.resetConcurrentModification();
+        it.moveTo(fs);
+        if (it.isValid()) {
+          heapify_up(it, i, 1);
+          ++i;
+        } else {
+          // swap this iterator with the last possibly valid one
+          // lvi might be equal to i, this will not be a problem
+          this.indexes[i] = this.indexes[lvi];
+          this.indexes[lvi] = it;
+          --lvi;
+        }
+      }
+      // configured to continue with forward iterations
+      this.wentForward = true;
+      this.lastValidIndex = lvi;
+      // Go back until we find a FS that is really smaller
+      while (true) {
+        moveToPrevious();
+        if (isValid()) {
+          int prev = get();
+          if (this.iicp.index.compare(prev, fs) != 0) {
+            moveToNext();
+            break;
+          }
+        } else {
+          moveToFirst();
+          break;
+        }
+      }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.uima.cas.impl.LowLevelIterator#moveToNext()
+     */
+    public void inc() {
+      moveToNext();
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.uima.cas.impl.LowLevelIterator#moveToPrevious()
+     */
+    public void dec() {
+      moveToPrevious();
+    }
+
+    public int ll_indexSize() {
+      return this.iicp.size();
+    }
+
+    public LowLevelIndex ll_getIndex() {
+      return this.iicp.index;
+    }
+
+  }
+
+  /**
+   * The iterator implementation for indexes. Tricky because the iterator needs to be able to move
+   * backwards as well as forwards.
+   */
+  private class LeafPointerIterator implements IntPointerIterator, LowLevelIterator {
+
+    // The IICP
+    private IndexIteratorCachePair iicp;
+
+    // An array of integer arrays, one for each subtype.
+    private ComparableIntPointerIterator index;
+
+    private LeafPointerIterator() {
+      super();
+    }
+
+    private void initPointerIterator(IndexIteratorCachePair iicp0) {
+      this.iicp = iicp0;
+      // Make sure the iterator cache exists.
+      final ArrayList<FSLeafIndexImpl<?>> iteratorCache = iicp0.iteratorCache;
+      final FSLeafIndexImpl<?> leafIndex = iteratorCache.get(0);
+      this.index = leafIndex.pointerIterator(leafIndex,
+          FSIndexRepositoryImpl.this.detectIllegalIndexUpdates,
+          ((TypeImpl) leafIndex.getType()).getCode());
+    }
+
+    private LeafPointerIterator(IndexIteratorCachePair iicp) {
+      super();
+      initPointerIterator(iicp);
+      moveToFirst();
+    }
+
+    private LeafPointerIterator(IndexIteratorCachePair iicp, int fs) {
+      super();
+      initPointerIterator(iicp);
+      moveTo(fs);
+    }
+
+    private ComparableIntPointerIterator checkConcurrentModification() {
+      if (this.index.isConcurrentModification()) {
+        throw new ConcurrentModificationException();
+      }
+      return this.index;
+    }
+
+    public boolean isValid() {
+      return this.index.isValid();
+    }
+
+    public void moveToLast() {
+      this.index.resetConcurrentModification();
+      this.index.moveToLast();
+    }
+
+    public void moveToFirst() {
+      this.index.resetConcurrentModification();
+      this.index.moveToFirst();
+    }
+
+    public void moveToNext() {
+      checkConcurrentModification().inc();
+    }
+
+    public void moveToPrevious() {
+      checkConcurrentModification().dec();
+    }
+
+    public int get() throws NoSuchElementException {
+      return ll_get();
+    }
+
+    public int ll_get() {
+      if (!isValid()) {
+        throw new NoSuchElementException();
+      }
+      return checkConcurrentModification().get();
+    }
+
+    public Object copy() {
+      // If this.isValid(), return a copy pointing to the same element.
+      if (this.isValid()) {
+        return new LeafPointerIterator(this.iicp, this.get());
+      }
+      // Else, create a copy that is also not valid.
+      final LeafPointerIterator pi = new LeafPointerIterator(this.iicp);
+      pi.moveToFirst();
+      pi.moveToPrevious();
+      return pi;
+    }
+
+    /**
+     * @see org.apache.uima.internal.util.IntPointerIterator#moveTo(int)
+     */
+    public void moveTo(int fs) {
+      this.index.resetConcurrentModification();
+      this.index.moveTo(fs);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.uima.cas.impl.LowLevelIterator#moveToNext()
+     */
+    public void inc() {
+      checkConcurrentModification().inc();
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.uima.cas.impl.LowLevelIterator#moveToPrevious()
+     */
+    public void dec() {
+      checkConcurrentModification().dec();
+    }
+
+    public int ll_indexSize() {
+      return this.iicp.size();
+    }
+
+    public LowLevelIndex ll_getIndex() {
+      return this.iicp.index;
+    }
+
+  }
+
+  private class IndexImpl<T extends FeatureStructure> implements FSIndex<T>, FSIndexImpl {
+
+    private final IndexIteratorCachePair iicp;
+
+    private IndexImpl(IndexIteratorCachePair iicp) {
+      super();
+      this.iicp = iicp;
+    }
+
+    public int ll_compare(int ref1, int ref2) {
+      return this.iicp.index.ll_compare(ref1, ref2);
+    }
+
+    public int getIndexingStrategy() {
+      return this.iicp.index.getIndexingStrategy();
+    }
+
+    public FSIndexComparator getComparator() {
+      return this.iicp.index.getComparator();
+    }
+
+    protected IntComparator getIntComparator() {
+      return this.iicp.index.getIntComparator();
+    }
+
+    public void flush() {
+      this.iicp.index.flush();
+    }
+
+    /**
+     * @see org.apache.uima.cas.FSIndex#compare(FeatureStructure, FeatureStructure)
+     */
+    public int compare(FeatureStructure fs1, FeatureStructure fs2) {
+      return this.iicp.index.compare(fs1, fs2);
+    }
+
+    /**
+     * @see org.apache.uima.cas.FSIndex#contains(FeatureStructure)
+     */
+    public boolean contains(FeatureStructure fs) {
+      return this.iicp.index.contains(fs);
+    }
+
+    public FeatureStructure find(FeatureStructure fs) {
+      return this.iicp.index.find(fs);
+    }
+
+    /**
+     * @see org.apache.uima.cas.FSIndex#getType()
+     */
+    public Type getType() {
+      return this.iicp.index.getType();
+    }
+
+    /**
+     * @see org.apache.uima.cas.FSIndex#iterator()
+     */
+    public FSIterator<T> iterator() {
+      return new FSIteratorWrapper<T>(createPointerIterator(this.iicp),
+          FSIndexRepositoryImpl.this.cas);
+    }
+
+    /**
+     * @see org.apache.uima.cas.FSIndex#iterator(FeatureStructure)
+     */
+    public FSIterator<T> iterator(FeatureStructure fs) {
+      return new FSIteratorWrapper<T>(createPointerIterator(this.iicp,
+          ((FeatureStructureImpl) fs).getAddress()), FSIndexRepositoryImpl.this.cas);
+    }
+
+    public IntPointerIterator getIntIterator() {
+      return createPointerIterator(this.iicp);
+    }
+
+    /**
+     * @see org.apache.uima.cas.FSIndex#size()
+     */
+    public int size() {
+      this.iicp.createIndexIteratorCache();
+      // int size = this.iicp.index.size();
+      int size = 0;
+      final ArrayList<FSLeafIndexImpl<?>> subIndex = this.iicp.iteratorCache;
+      final int max = subIndex.size();
+      for (int i = 0; i < max; i++) {
+        size += subIndex.get(i).size();
+      }
+      return size;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.uima.cas.impl.LowLevelIndex#ll_iterator()
+     */
+    public LowLevelIterator ll_iterator() {
+      return (LowLevelIterator) createPointerIterator(this.iicp);
+    }
+
+    public LowLevelIterator ll_rootIterator() {
+      this.iicp.createIndexIteratorCache();
+      return new LeafPointerIterator(this.iicp);
+    }
+
+    public LowLevelIterator ll_iterator(boolean ambiguous) {
+      if (ambiguous) {
+        return this.ll_iterator();
+      }
+      return new LLUnambiguousIteratorImpl(this.ll_iterator(), this.iicp.index.lowLevelCAS);
+    }
+
+  }
+
+  // private class AnnotIndexImpl
+  // extends IndexImpl
+  // implements AnnotationIndex, FSIndexImpl {
+  //
+  // private AnnotIndexImpl(IndexIteratorCachePair iicp) {
+  // super(iicp);
+  // }
+  //
+  // public FSIterator subiterator(AnnotationFS annot) {
+  // return new Subiterator(
+  // this.getIntIterator(),
+  // annot,
+  // (CASImpl) FSIndexRepositoryImpl.this.cas,
+  // this.getIntComparator());
+  // }
+  //
+  // public FSIterator subiterator(AnnotationFS annot, boolean ambiguous) {
+  // if (ambiguous) {
+  // return subiterator(annot);
+  // } else {
+  // return new UnambiguousIterator(subiterator(annot), this);
+  // }
+  // }
+  //
+  // public FSIterator unambigousIterator() {
+  // return new UnambiguousIterator(iterator(), this);
+  // }
+  //
+  // }
+
+  /**
+   * The default size of an index.
+   */
+  public static final int DEFAULT_INDEX_SIZE = 100;
+
+  // A reference to the CAS.
+  private CASImpl cas;
+
+  // A reference to the type system.
+  private TypeSystemImpl typeSystem;
+
+  // Is the index repository locked?
+  private boolean locked = false;
+
+  // An array of ArrayLists, one for each type in the type hierarchy.
+  // The ArrayLists are unordered lists of IndexIteratorCachePairs for
+  // that type.
+  private ArrayList<IndexIteratorCachePair>[] indexArray;
+
+  // an array of ints, one for each type in the type hierarchy.
+  // Used to enable iterators to detect modifications (adds / removes)
+  // to indexes they're iterating over while they're iterating over them.
+  // not private so it can be seen by FSLeafIndexImpl
+  int[] detectIllegalIndexUpdates;
+
+  // A map from names to IndexIteratorCachePairs. Different names may map to
+  // the same index.
+  private HashMap<String, IndexIteratorCachePair> name2indexMap;
+
+  private LinearTypeOrderBuilder defaultOrderBuilder = null;
+
+  private LinearTypeOrder defaultTypeOrder = null;
+
+  private IntVector indexUpdates;
+
+  private BitSet indexUpdateOperation;
+
+  private boolean logProcessed;
+
+  private IntSet fsAddedToIndex;
+
+  private IntSet fsDeletedFromIndex;
+
+  private IntSet fsReindexed;
+
+  // Monitor indexes used to optimize getIndexedFS and flush
+  private IntVector usedIndexes;
+
+  private boolean[] isUsed;
+
+  @SuppressWarnings("unused")
+  private FSIndexRepositoryImpl() {
+    super();
+  }
+
+  /**
+   * Constructor.
+   * 
+   * @param cas
+   */
+  FSIndexRepositoryImpl(CASImpl cas) {
+    super();
+    this.cas = cas;
+    this.typeSystem = cas.getTypeSystemImpl();
+    this.name2indexMap = new HashMap<String, IndexIteratorCachePair>();
+    this.indexUpdates = new IntVector();
+    this.indexUpdateOperation = new BitSet();
+    this.fsAddedToIndex = new IntSet();
+    this.fsDeletedFromIndex = new IntSet();
+    this.fsReindexed = new IntSet();
+    this.logProcessed = false;
+    init();
+  }
+
+  /**
+   * Constructor for views.
+   * 
+   * @param cas
+   * @param baseIndexRepository
+   */
+  FSIndexRepositoryImpl(CASImpl cas, FSIndexRepositoryImpl baseIndexRepo) {
+    super();
+    this.cas = cas;
+    this.typeSystem = cas.getTypeSystemImpl();
+    this.name2indexMap = new HashMap<String, IndexIteratorCachePair>();
+    this.indexUpdates = new IntVector();
+    this.indexUpdateOperation = new BitSet();
+    this.fsAddedToIndex = new IntSet();
+    this.fsDeletedFromIndex = new IntSet();
+    this.fsReindexed = new IntSet();
+    this.logProcessed = false;
+    init();
+    final Set<String> keys = baseIndexRepo.name2indexMap.keySet();
+    if (!keys.isEmpty()) {
+      final Iterator<String> keysIter = keys.iterator();
+      while (keysIter.hasNext()) {
+        final String key = keysIter.next();
+        final IndexIteratorCachePair iicp = baseIndexRepo.name2indexMap.get(key);
+        createIndexNoQuestionsAsked(iicp.index.getComparator(), key,
+            iicp.index.getIndexingStrategy());
+      }
+    }
+    this.defaultOrderBuilder = baseIndexRepo.defaultOrderBuilder;
+    this.defaultTypeOrder = baseIndexRepo.defaultTypeOrder;
+  }
+
+  /**
+   * Initialize data. Called from the constructor.
+   */
+  @SuppressWarnings("unchecked")
+  private void init() {
+    final TypeSystemImpl ts = this.typeSystem;
+    // Type counting starts at 1.
+    final int numTypes = ts.getNumberOfTypes() + 1;
+    // Can't instantiate arrays of generic types.
+    this.indexArray = new ArrayList[numTypes];
+    for (int i = 1; i < numTypes; i++) {
+      this.indexArray[i] = new ArrayList<IndexIteratorCachePair>();
+    }
+    this.detectIllegalIndexUpdates = new int[numTypes];
+    for (int i = 0; i < this.detectIllegalIndexUpdates.length; i++) {
+      this.detectIllegalIndexUpdates[i] = Integer.MIN_VALUE;
+    }
+    this.usedIndexes = new IntVector();
+    this.isUsed = new boolean[numTypes];
+  }
+
+  /**
+   * Reset all indexes.
+   */
+  public void flush() {
+    if (!this.locked) {
+      return;
+    }
+    int max;
+    ArrayList<IndexIteratorCachePair> v;
+
+    // Do nothing really fast!
+    if (this.usedIndexes.size() == 0) {
+      return;
+    }
+
+    for (int i = 0; i < this.usedIndexes.size(); i++) {
+      this.isUsed[this.usedIndexes.get(i)] = false;
+      v = this.indexArray[this.usedIndexes.get(i)];
+      max = v.size();
+      for (int j = 0; j < max; j++) {
+        v.get(j).index.flush();
+      }
+    }
+    this.indexUpdates.removeAllElements();
+    this.indexUpdateOperation.clear();
+    this.fsAddedToIndex = new IntSet();
+    this.fsDeletedFromIndex = new IntSet();
+    this.fsReindexed = new IntSet();
+    this.logProcessed = false;
+    this.usedIndexes.removeAllElements();
+  }
+
+  public void addFS(int fsRef) {
+    ll_addFS(fsRef);
+  }
+
+  private IndexIteratorCachePair addNewIndex(FSIndexComparator comparator, int indexType) {
+    return addNewIndex(comparator, DEFAULT_INDEX_SIZE, indexType);
+  }
+
+  /**
+   * This is where the actual index gets created.
+   */
+  private IndexIteratorCachePair addNewIndex(FSIndexComparator comparator, int initialSize,
+      int indexType) {
+    final Type type = comparator.getType();
+    final int typeCode = ((TypeImpl) type).getCode();
+    if (typeCode >= this.indexArray.length) {
+      // assert(false);
+    }
+    final ArrayList<IndexIteratorCachePair> indexVector = this.indexArray[typeCode];
+    // final int vecLen = indexVector.size();
+    FSLeafIndexImpl<?> ind;
+    switch (indexType) {
+    case FSIndex.SET_INDEX: {
+      ind = new FSRBTSetIndex(this.cas, type, indexType);
+      break;
+    }
+    case FSIndex.BAG_INDEX: {
+      ind = new FSBagIndex(this.cas, type, initialSize, indexType);
+      break;
+    }
+    case FSIndex.DEFAULT_BAG_INDEX: {
+      ind = new FSBagIndex(this.cas, type, initialSize, indexType);
+      break;
+    }
+    default: {
+      // SORTED_INDEX is the default. We don't throw any errors, if the
+      // code
+      // is unknown, we just create a sorted index (with duplicates).
+      // ind = new FSRBTIndex(this.cas, type, FSIndex.SORTED_INDEX);
+      ind = new FSIntArrayIndex(this.cas, type, initialSize, FSIndex.SORTED_INDEX);
+      break;
+    }
+    }
+    // ind = new FSRBTIndex(this.cas, type);
+    // ind = new FSVectorIndex(this.cas, initialSize);
+    ind.init(comparator);
+    final IndexIteratorCachePair iicp = new IndexIteratorCachePair();
+    iicp.index = ind;
+    indexVector.add(iicp);
+    return iicp;
+  }
+
+  /*
+   * private IndexIteratorCachePair addIndex( FSIndexComparator comparator, int initialSize) { final
+   * Type type = comparator.getType(); final int typeCode = ((TypeImpl) type).getCode(); final
+   * Vector indexVector = this.indexArray[typeCode]; final int vecLen = indexVector.size();
+   * FSLeafIndexImpl ind;
+   * 
+   * for (int i = 0; i < vecLen; i++) { ind = ((IndexIteratorCachePair) indexVector.get(i)).index;
+   * if (comparator.equals(ind.getComparator())) { return null; } }
+   * 
+   * ind = new FSRBTIndex(this.cas, type); // ind = new FSVectorIndex(this.cas, initialSize);
+   * ind.init(comparator); IndexIteratorCachePair iicp = new IndexIteratorCachePair(); iicp.index =
+   * ind; indexVector.add(iicp); return iicp; }
+   */
+  // private IndexIteratorCachePair addIndexRecursive(FSIndexComparator
+  // comparator) {
+  // final FSIndexComparatorImpl compCopy =
+  // ((FSIndexComparatorImpl) comparator).copy();
+  // return addIndexRec(compCopy);
+  // }
+  private IndexIteratorCachePair addNewIndexRecursive(FSIndexComparator comparator, int indexType) {
+    final FSIndexComparatorImpl compCopy = ((FSIndexComparatorImpl) comparator).copy();
+    return addNewIndexRec(compCopy, indexType);
+  }
+
+  private static final int findIndex(ArrayList<IndexIteratorCachePair> indexes,
+      FSIndexComparator comp,
+      int indexType) {
+    FSIndexComparator indexComp;
+    final int max = indexes.size();
+    for (int i = 0; i < max; i++) {
+      FSLeafIndexImpl index = indexes.get(i).index;
+      if (index.getIndexingStrategy() != indexType) {
+        continue;
+      }
+      indexComp = index.getComparator();
+      if (comp.equals(indexComp)) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  /*
+   * // Will modify comparator, so call with copy. private IndexIteratorCachePair
+   * addIndexRec(FSIndexComparator comp) { FSIndexComparator compCopy; IndexIteratorCachePair cp =
+   * this.addIndex(comp); if (cp == null) { return null; // The index already exists. } final Type
+   * superType = comp.getType(); final Vector types =
+   * this.typeSystem.getDirectlySubsumedTypes(superType); final int max = types.size(); for (int i =
+   * 0; i < max; i++) { compCopy = ((FSIndexComparatorImpl)comp).copy(); compCopy.setType((Type)
+   * types.get(i)); addIndexRec(compCopy); } return cp; }
+   */
+  // Will modify comparator, so call with copy.
+  private IndexIteratorCachePair addNewIndexRec(FSIndexComparator comparator, int indexType) {
+    final IndexIteratorCachePair iicp = this.addNewIndex(comparator, indexType);
+    if (indexType == FSIndex.DEFAULT_BAG_INDEX) {
+      // In this special case, we do not add indeces for subtypes.
+      return iicp;
+    }
+    final Type superType = comparator.getType();
+    final Vector<Type> types = this.typeSystem.getDirectlySubsumedTypes(superType);
+    final int max = types.size();
+    FSIndexComparator compCopy;
+    for (int i = 0; i < max; i++) {
+      compCopy = ((FSIndexComparatorImpl) comparator).copy();
+      compCopy.setType(types.get(i));
+      addNewIndexRec(compCopy, indexType);
+    }
+    return iicp;
+  }
+
+  private static final ArrayList<Type> getAllSubsumedTypes(Type t, TypeSystem ts) {
+    final ArrayList<Type> v = new ArrayList<Type>();
+    addAllSubsumedTypes(t, ts, v);
+    return v;
+  }
+
+  private static final void addAllSubsumedTypes(Type t, TypeSystem ts, ArrayList<Type> v) {
+    v.add(t);
+    final List<Type> sub = ts.getDirectSubtypes(t);
+    final int len = sub.size();
+    for (int i = 0; i < len; i++) {
+      addAllSubsumedTypes(sub.get(i), ts, v);
+    }
+  }
+
+  /**
+   * @see org.apache.uima.cas.admin.FSIndexRepositoryMgr#commit()
+   */
+  public void commit() {
+    // Will create the default type order if it doesn't exist at this point.
+    getDefaultTypeOrder();
+    this.locked = true;
+  }
+
+  public LinearTypeOrder getDefaultTypeOrder() {
+    if (this.defaultTypeOrder == null) {
+      if (this.defaultOrderBuilder == null) {
+        this.defaultOrderBuilder = new LinearTypeOrderBuilderImpl(this.typeSystem);
+      }
+      try {
+        this.defaultTypeOrder = this.defaultOrderBuilder.getOrder();
+      } catch (final CASException e) {
+        // Since we're doing this on an existing type names, we can't
+        // get here.
+      }
+    }
+    return this.defaultTypeOrder;
+  }
+
+  public LinearTypeOrderBuilder getDefaultOrderBuilder() {
+    if (this.defaultOrderBuilder == null) {
+      this.defaultOrderBuilder = new LinearTypeOrderBuilderImpl(this.typeSystem);
+    }
+    return this.defaultOrderBuilder;
+  }
+
+  void setDefaultTypeOrder(LinearTypeOrder order) {
+    this.defaultTypeOrder = order;
+  }
+
+  /**
+   * @see org.apache.uima.cas.admin.FSIndexRepositoryMgr#createIndex(FSIndexComparator, String)
+   */
+  public boolean createIndex(FSIndexComparator comp, String label, int indexType)
+      throws CASAdminException {
+    if (this.locked) {
+      throw new CASAdminException(CASAdminException.REPOSITORY_LOCKED);
+    }
+    return createIndexNoQuestionsAsked(comp, label, indexType);
+  }
+
+  /**
+   * This is public only until the xml specifier format supports specifying index kinds (set, bag
+   * etc.).
+   * 
+   * @param comp
+   * @param label
+   * @param indexType
+   * @return boolean
+   */
+  public boolean createIndexNoQuestionsAsked(FSIndexComparator comp, String label, int indexType) {
+    IndexIteratorCachePair cp = this.name2indexMap.get(label);
+    // Now check if the index already exists.
+    if (cp == null) {
+      // The name is new.
+      cp = this.addNewIndexRecursive(comp, indexType);
+      this.name2indexMap.put(label, cp);
+      return true;
+    }
+    // For now, just return false if the label already exists.
+    return false;
+    // // An index has previously been registered for this name. We need to
+    // // compare the types to see if the new addition is compatible with
+    // the
+    // // pre-existing one. There are three cases: the new type can be a
+    // sub-type
+    // // of the old one, in which case we don't need to do anything; or,
+    // the
+    // // new type is a super-type of the old one, in which case we add the
+    // new
+    // // index while keeping the old one; or, there is no subsumption
+    // relation,
+    // // in which case we can't add the index.
+    // Type oldType = cp.index.getType(); // Get old type from the index.
+    // Type newType = comp.getType(); // Get new type from comparator.
+    // if (this.typeSystem.subsumes(oldType, newType)) {
+    // // We don't need to do anything.
+    // return true;
+    // } else if (this.typeSystem.subsumes(newType, oldType)) {
+    // // Add the index, subsuming the old one.
+    // cp = this.addIndexRecursive(comp);
+    // // Replace the old index with the new one in the map.
+    // this.name2indexMap.put(label, cp);
+    // return true;
+    // } else {
+    // // Can't add index under that name.
+    // return false;
+    // }
+    // }
+  }
+
+  /**
+   * @see org.apache.uima.cas.admin.FSIndexRepositoryMgr#getIndexes()
+   */
+  public Iterator<FSIndex<FeatureStructure>> getIndexes() {
+    final ArrayList<FSIndex<FeatureStructure>> indexList = new ArrayList<FSIndex<FeatureStructure>>();
+    final Iterator<String> it = this.getLabels();
+    String label;
+    while (it.hasNext()) {
+      label = it.next();
+      indexList.add(getIndex(label));
+    }
+    return indexList.iterator();
+  }
+
+  /**
+   * @see org.apache.uima.cas.admin.FSIndexRepositoryMgr#getLabels()
+   */
+  public Iterator<String> getLabels() {
+    return this.name2indexMap.keySet().iterator();
+  }
+
+  /**
+   * Get the labels for a specific comparator.
+   * 
+   * @param comp
+   *          The comparator.
+   * @return An iterator over the labels.
+   */
+  public Iterator<String> getLabels(FSIndexComparator comp) {
+    final ArrayList<String> labels = new ArrayList<String>();
+    final Iterator<String> it = this.getLabels();
+    String label;
+    while (it.hasNext()) {
+      label = it.next();
+      if (this.name2indexMap.get(label).index.getComparator().equals(comp)) {
+        labels.add(label);
+      }
+    }
+    return labels.iterator();
+  }
+
+  /**
+   * @see org.apache.uima.cas.FSIndexRepository#getIndex(String, Type)
+   */
+  public FSIndex<FeatureStructure> getIndex(String label, Type type) {
+    final IndexIteratorCachePair iicp = this.name2indexMap.get(label);
+    if (iicp == null) {
+      return null;
+    }
+    // Why is this necessary?
+    // probably because we don't support indexes over FSArray<some-particular-type>
+    if (type.isArray()) {
+      final Type componentType = type.getComponentType();
+      if ((componentType != null) && !componentType.isPrimitive()
+          && !componentType.getName().equals(CAS.TYPE_NAME_TOP)) {
+        return null;
+      }
+    }
+    final Type indexType = iicp.index.getType();
+    if (!this.typeSystem.subsumes(indexType, type)) {
+      final CASRuntimeException cre = new CASRuntimeException(
+          CASRuntimeException.TYPE_NOT_IN_INDEX, new String[] { label, type.getName(),
+              indexType.getName() });
+      throw cre;
+    }
+    final int typeCode = ((TypeImpl) type).getCode();
+    final ArrayList<IndexIteratorCachePair> inds = this.indexArray[typeCode];
+    // Since we found an index for the correct type, find() must return a
+    // valid result -- unless this is a special auto-index.
+    final int indexCode = findIndex(inds, iicp.index.getComparator(), iicp.index.getIndexingStrategy());
+    if (indexCode < 0) {
+      return null;
+    }
+    // assert((indexCode >= 0) && (indexCode < inds.size()));
+    return new IndexImpl<FeatureStructure>(inds.get(indexCode));
+    // return ((IndexIteratorCachePair)inds.get(indexCode)).index;
+  }
+  
+
+  /**
+   * @see org.apache.uima.cas.FSIndexRepository#getIndex(String)
+   */
+  public FSIndex<FeatureStructure> getIndex(String label) {
+    final IndexIteratorCachePair iicp = this.name2indexMap.get(label);
+    if (iicp == null) {
+      return null;
+    }
+    return new IndexImpl<FeatureStructure>(iicp);
+    // return ((IndexIteratorCachePair)name2indexMap.get(label)).index;
+  }
+
+  public IntPointerIterator getIntIteratorForIndex(String label) {
+    final IndexImpl<FeatureStructure> index = (IndexImpl<FeatureStructure>) getIndex(label);
+    if (index == null) {
+      return null;
+    }
+    return createPointerIterator(index.iicp);
+  }
+
+  public IntPointerIterator getIntIteratorForIndex(String label, Type type) {
+    final IndexImpl<FeatureStructure> index = (IndexImpl<FeatureStructure>) getIndex(label, type);
+    if (index == null) {
+      return null;
+    }
+    return createPointerIterator(index.iicp);
+  }
+
+  public int getIndexSize(Type type) {
+    final int typeCode = ((TypeImpl) type).getCode();
+    final ArrayList<IndexIteratorCachePair> indexVector = this.indexArray[typeCode];
+    if (indexVector.size() == 0) {
+      // No index for this type exists.
+      return 0;
+    }
+    int numFSs = indexVector.get(0).index.size();
+    final Vector<Type> typeVector = this.typeSystem.getDirectlySubsumedTypes(type);
+    final int max = typeVector.size();
+    for (int i = 0; i < max; i++) {
+      numFSs += getIndexSize(typeVector.get(i));
+    }
+    return numFSs;
+  }
+  
+  /**
+   * Remove all instances of a particular type (but not its subtypes) from all indexes
+   * @param type
+   */
+  public void removeAllExcludingSubtypes(Type type) {
+    final int typeCode = ((TypeImpl) type).getCode();
+    incrementIllegalIndexUpdateDetector(typeCode);
+    // get a list of all indexes defined over this type
+    // Includes indexes defined on supertypes of this type
+    final ArrayList<IndexIteratorCachePair> allIndexesForType = this.indexArray[typeCode];
+    for (IndexIteratorCachePair iicp : allIndexesForType) {
+      iicp.index.flush();
+    }
+  }
+  
+  /**
+   * Remove all instances of a particular type (including its subtypes) from all indexes
+   * @param type
+   */
+  public void removeAllIncludingSubtypes(Type type) {
+    removeAllExcludingSubtypes(type);
+    List<Type> subtypes = this.typeSystem.getDirectSubtypes(type);
+    for (Type subtype : subtypes) {
+      removeAllIncludingSubtypes(subtype);
+    }
+  }
+  
+
+  /**
+   * @see org.apache.uima.cas.admin.FSIndexRepositoryMgr#createComparator()
+   */
+  public FSIndexComparator createComparator() {
+    return new FSIndexComparatorImpl(this.cas);
+  }
+
+  /**
+   * @see org.apache.uima.cas.admin.FSIndexRepositoryMgr#isCommitted()
+   */
+  public boolean isCommitted() {
+    return this.locked;
+  }
+
+  /**
+   * @see org.apache.uima.cas.admin.FSIndexRepositoryMgr#createIndexComparator()
+   */
+  // public FSIndexComparator createIndexComparator() {
+  // return new FSIndexComparatorImpl(this.cas);
+  // }
+  /**
+   * @see org.apache.uima.cas.admin.FSIndexRepositoryMgr#createIndex(org.apache.uima.cas.admin.FSIndexComparator,
+   *      java.lang.String)
+   */
+  public boolean createIndex(FSIndexComparator comp, String label) throws CASAdminException {
+    return createIndex(comp, label, FSIndex.SORTED_INDEX);
+  }
+
+  // ///////////////////////////////////////////////////////////////////////////
+  // Serialization support
+
+  /**
+   * For one particular view (the one associated with this instance of FsIndexRepositoryImpl),
+   * return an array containing all FSs in any defined index, in this view. 
+   * This is intended to be used for serialization.
+   * 
+   * Note that duplicate entries are removed, and the results are sorted by FS address.
+   * 
+   * The order in which FSs occur in the array does not reflect the order in which they
+   * were added to the repository. This means that set indexes deserialized from this list may
+   * contain different but equal elements than the original index.
+   */
+  public int[] getIndexedFSs() {
+    final IntVector v = new IntVector();
+    IndexIteratorCachePair iicp;
+    IntPointerIterator it;
+    ArrayList<IndexIteratorCachePair> iv, cv;
+    // We may need to profile this. If this is a bottleneck, use a different
+    // implementation.
+    IntVector indexedFSs = new IntVector();
+    int jMax, indStrat;
+    // Iterate over index by type, with something in there
+    for (int i = 0; i < this.usedIndexes.size(); i++) {
+      iv = this.indexArray[this.usedIndexes.get(i)];
+      // Iterate over the indexes for the type.
+      jMax = iv.size();
+      // Create a vector of IICPs. If there is at least one sorted or bag
+      // index, pick one arbitrarily and add its FSs (since it contains all
+      // FSs that all other indexes for the same type contain). If there are
+      // only set indexes, create a set of the FSs in those indexes, since they
+      // may all contain different elements (different FSs that have the same "key"
+      //   are duplicates for one index, but may not be duplicates for a different one).
+      cv = new ArrayList<IndexIteratorCachePair>();
+      for (int j = 0; j < jMax; j++) {
+        iicp = iv.get(j);
+        indStrat = iicp.index.getIndexingStrategy();
+        if (indStrat == FSIndex.SET_INDEX) {
+          cv.add(iicp);
+        } else {
+          cv.clear();  // only need to save this one
+          cv.add(iicp);
+          break;
+        }
+      }
+      if (cv.size() > 0) {
+        // Note: This next loop removes duplicates (and also sorts
+        // the fs addrs associated with one type)
+        // Duplicates arise from having mulitple sets combined, and
+        // also if a non-set index had the same identical FS added
+        // multiple times.
+        indexedFSs.removeAllElements();
+        for (int k = 0; k < cv.size(); k++) {
+          it = cv.get(k).index.refIterator();
+          while (it.isValid()) {
+            indexedFSs.add(it.get());
+            it.inc();
+          }
+        }
+        // sort and remove duplicates
+        indexedFSs.sortDedup();
+        v.add(indexedFSs.getArray(), 0, indexedFSs.size());  // bulk add of all elements
+//        for (int k = 0; k < set.size(); k++) {
+//          v.add(set.get(k));
+//        }
+      }
+    }
+    return v.toArray();
+  }
+
+  /**
+   * @see org.apache.uima.cas.FSIndexRepository#addFS(org.apache.uima.cas.FeatureStructure)
+   */
+  public void addFS(FeatureStructure fs) {
+    addFS(((FeatureStructureImpl) fs).getAddress());
+  }
+
+  private void incrementIllegalIndexUpdateDetector(int typeCode) {
+    this.detectIllegalIndexUpdates[typeCode]++;
+  }
+
+  /**
+   * @see org.apache.uima.cas.FSIndexRepository#removeFS(org.apache.uima.cas.FeatureStructure)
+   */
+  public void removeFS(FeatureStructure fs) {
+    ll_removeFS(this.cas.ll_getFSRef(fs));
+
+    // final int typeCode =
+    // this.cas.ll_getFSRefType(this.cas.ll_getFSRef(fs));
+    // // final TypeImpl type = (TypeImpl) fs.getType();
+    // ArrayList idxList = this.indexArray[typeCode];
+    // final int max = idxList.size();
+    // incrementIllegalIndexUpdateDetector(typeCode);
+    // for (int i = 0; i < max; i++) {
+    // ((IndexIteratorCachePair) idxList.get(i)).index.deleteFS(fs);
+    // }
+  }
+
+  public void removeFS(int fsRef) {
+    ll_removeFS(fsRef);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.uima.cas.admin.FSIndexRepositoryMgr#createTypeSortOrder()
+   */
+  public LinearTypeOrderBuilder createTypeSortOrder() {
+    final LinearTypeOrderBuilder orderBuilder = new LinearTypeOrderBuilderImpl(this.typeSystem);
+    if (this.defaultOrderBuilder == null) {
+      this.defaultOrderBuilder = orderBuilder;
+    }
+    return orderBuilder;
+  }
+
+  // private static final void bubbleSort(Object[] array, int end)
+  // {
+  // int comp;
+  // Object tmp;
+  // for (int i = (end - 1); i >= 0; i--)
+  // {
+  // for (int j = 1; j <= i; j++)
+  // {
+  // comp = ((Comparable) array[j - 1]).compareTo(array[j]);
+  // if (comp > 0)
+  // {
+  // tmp = array[j - 1];
+  // array[j - 1] = array[j];
+  // array[j] = tmp;
+  // }
+  // }
+  // }
+  // }
+
+  public LowLevelIndex ll_getIndex(String indexName) {
+    return (LowLevelIndex) getIndex(indexName);
+  }
+
+  public LowLevelIndex ll_getIndex(String indexName, int typeCode) {
+    if (!this.typeSystem.isType(typeCode) || !this.cas.ll_isRefType(typeCode)) {
+      final LowLevelException e = new LowLevelException(LowLevelException.INVALID_INDEX_TYPE);
+      e.addArgument(Integer.toString(typeCode));
+      throw e;
+    }
+    return (LowLevelIndex) getIndex(indexName, this.typeSystem.ll_getTypeForCode(typeCode));
+  }
+
+  public final void ll_addFS(int fsRef, boolean doChecks) {
+    if (doChecks) {
+      this.cas.checkFsRef(fsRef);
+      this.cas.ll_isRefType(this.cas.ll_getFSRefType(fsRef));
+    }
+    ll_addFS(fsRef);
+  }
+
+  public void ll_addFS(int fsRef) {
+    // Determine type of FS.
+    final int typeCode = this.cas.getHeapValue(fsRef);
+    // indicate this type's indexes are being modified
+    // in case an iterator is simultaneously active over this type
+    incrementIllegalIndexUpdateDetector(typeCode);
+    // Get the indexes for the type.
+    final ArrayList<IndexIteratorCachePair> indexes = this.indexArray[typeCode];
+    // Add fsRef to all indexes.
+    final int size = indexes.size();
+    for (int i = 0; i < size; i++) {
+      indexes.get(i).index.insert(fsRef);
+    }
+    if (size == 0) {
+      // lazily create a default bag index for this type
+      final Type type = this.typeSystem.ll_getTypeForCode(typeCode);
+      final String defIndexName = getAutoIndexNameForType(type);
+      final FSIndexComparator comparator = createComparator();
+      comparator.setType(type);
+      createIndexNoQuestionsAsked(comparator, defIndexName, FSIndex.DEFAULT_BAG_INDEX);
+      assert this.indexArray[typeCode].size() == 1;
+      // add the FS to the bag index
+      this.indexArray[typeCode].get(0).index.insert(fsRef);
+    }
+    if (this.cas.getCurrentMark() != null) {
+      logIndexOperation(fsRef, true);
+    }
+    if (!this.isUsed[typeCode]) {
+      // mark this index as used
+      this.isUsed[typeCode] = true;
+      this.usedIndexes.add(typeCode);
+    }
+  }
+
+  private static final String getAutoIndexNameForType(Type type) {
+    return "_" + type.getName() + "_GeneratedIndex";
+  }
+
+  public void ll_removeFS(int fsRef) {
+    final int typeCode = this.cas.ll_getFSRefType(fsRef);
+    incrementIllegalIndexUpdateDetector(typeCode);
+    final ArrayList<IndexIteratorCachePair> idxList = this.indexArray[typeCode];
+    final int max = idxList.size();
+    for (int i = 0; i < max; i++) {
+      idxList.get(i).index.remove(fsRef);
+    }
+    if (this.cas.getCurrentMark() != null) {
+      logIndexOperation(fsRef, false);
+    }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.uima.cas.FSIndexRepository#getAllIndexedFS(org.apache.uima.cas.Type)
+   */
+  public FSIterator<FeatureStructure> getAllIndexedFS(Type type) {
+    final List<FSIterator<FeatureStructure>> iteratorList = new ArrayList<FSIterator<FeatureStructure>>();
+    getAllIndexedFS(type, iteratorList);
+    return new FSIteratorAggregate<FeatureStructure>(iteratorList);
+  }
+
+  @SuppressWarnings("unchecked")
+  private final void getAllIndexedFS(Type type, List<FSIterator<FeatureStructure>> iteratorList) {
+    // Start by looking for an auto-index. If one exists, no other index exists.
+    final FSIndex<FeatureStructure> autoIndex = getIndex(getAutoIndexNameForType(type));
+    if (autoIndex != null) {
+      iteratorList.add(autoIndex.iterator());
+      // We found one of the special auto-indexes which don't inherit down the tree. So, we
+      // manually need to traverse the inheritance tree to look for more indexes. Note that
+      // this is not necessary when we have a regular index
+      final List<Type> subtypes = this.typeSystem.getDirectSubtypes(type);
+      for (int i = 0; i < subtypes.size(); i++) {
+        getAllIndexedFS(subtypes.get(i), iteratorList);
+      }
+      return;
+    }
+    // Attempt to find a non-set index first.
+    // If none found, then use the an arbitrary set index if any.
+    FSIndex setIndex = null;
+    final Iterator<String> iter = getLabels();
+    while (iter.hasNext()) {
+      final String label = iter.next();
+      final FSIndex index = getIndex(label);
+      // Ignore auto-indexes at this stage, they're handled above.
+      if (index.getIndexingStrategy() == FSIndex.DEFAULT_BAG_INDEX) {
+        continue;
+      }
+      if (this.typeSystem.subsumes(index.getType(), type)) {
+        if (index.getIndexingStrategy() != FSIndex.SET_INDEX) {
+          iteratorList.add(getIndex(label, type).iterator());
+          // Done, found non-set index.
+          return;
+        }
+        setIndex = getIndex(label, type);
+      }
+    }
+    // No sorted or bag index found for this type. If there was a set index,
+    // return an iterator for it.
+    if (setIndex != null) {
+      iteratorList.add(setIndex.iterator());
+      return;
+    }
+    // No index for this type was found at all. Since the auto-indexes are created on demand for
+    // each type, there may be gaps in the inheritance chain. So keep descending the inheritance
+    // tree looking for relevant indexes.
+    final List subtypes = this.typeSystem.getDirectSubtypes(type);
+    for (int i = 0; i < subtypes.size(); i++) {
+      getAllIndexedFS((Type) subtypes.get(i), iteratorList);
+    }
+  }
+
+  private void logIndexOperation(int fsRef, boolean added) {
+    this.indexUpdates.add(fsRef);
+    if (added) {
+      this.indexUpdateOperation.set(this.indexUpdates.size() - 1, added);
+    }
+    this.logProcessed = false;
+  }
+
+  // Delta Serialization support
+  /**
+   * Go through the journal, and use those entries to update
+   *   added, deleted, and reindexed lists
+   * in such a way as to guarantee:
+   *   a FS is in only one of these lists, (or in none)
+   *   
+   * For a journal "add-to-indexes" event:
+   *   fs in "deleted":  remove from "deleted", add to "reindexed"
+   *   fs in "reindexed": do nothing
+   *   fs in "added": do nothing
+   *   fs not in any of these: add to "added"
+   *   
+   * For a journal "remove-from-indexes" event:
+   *   fs in "added": remove from "added" (don't add to "deleted")
+   *   fs in "reindexed": remove from "reindexed" and add to "deleted")
+   *   fs in "deleted": do nothing
+   *   fs not in any of these: add to "deleted"
+   *   
+   * The journal is cleared after processing.
+   */
+  private void processIndexUpdates() {
+    for (int i = 0; i < this.indexUpdates.size(); i++) {
+      final int fsRef = this.indexUpdates.get(i);
+      final boolean added = this.indexUpdateOperation.get(i);
+      if (added) {
+        final int indexOfDeletedItem = this.fsDeletedFromIndex.indexOf(fsRef);
+        if (indexOfDeletedItem >= 0) {
+          this.fsDeletedFromIndex.remove(indexOfDeletedItem);
+          this.fsReindexed.add(fsRef);
+        } else if (this.fsReindexed.contains(fsRef)) {
+          continue;  // skip adding this to anything
+        } else {
+          this.fsAddedToIndex.add(fsRef);  // this is a set, so dups not added
+        }
+      } else {
+        final int indexOfaddedItem = this.fsAddedToIndex.indexOf(fsRef);
+        if (indexOfaddedItem >= 0) {
+          this.fsAddedToIndex.remove(indexOfaddedItem);
+        } else {
+          final int indexOfReindexedItem = this.fsReindexed.indexOf(fsRef);
+          if (indexOfReindexedItem >= 0) {
+            this.fsReindexed.remove(indexOfReindexedItem);
+            this.fsDeletedFromIndex.add(fsRef);
+          }
+          else {
+            this.fsDeletedFromIndex.add(fsRef);
+          }
+        }
+      }
+    }
+    this.logProcessed = true;
+    this.indexUpdates.removeAllElements();
+    this.indexUpdateOperation.clear();
+  }
+
+  public int[] getAddedFSs() {
+    if (!this.logProcessed) {
+      processIndexUpdates();
+    }
+    final int[] fslist = new int[this.fsAddedToIndex.size()];
+    for (int i = 0; i < fslist.length; i++) {
+      fslist[i] = this.fsAddedToIndex.get(i);
+    }
+    return fslist;
+  }
+
+  public int[] getDeletedFSs() {
+    if (!this.logProcessed) {
+      processIndexUpdates();
+    }
+    final int[] fslist = new int[this.fsDeletedFromIndex.size()];
+    for (int i = 0; i < fslist.length; i++) {
+      fslist[i] = this.fsDeletedFromIndex.get(i);
+    }
+    return fslist;
+  }
+
+  public int[] getReindexedFSs() {
+    if (!this.logProcessed) {
+      processIndexUpdates();
+    }
+    final int[] fslist = new int[this.fsReindexed.size()];
+    for (int i = 0; i < fslist.length; i++) {
+      fslist[i] = this.fsReindexed.get(i);
+    }
+    return fslist;
+  }
+
+  public boolean isModified() {
+    if (!this.logProcessed) {
+      processIndexUpdates();
+    }
+    return ((this.fsAddedToIndex.size() > 0) || (this.fsDeletedFromIndex.size() > 0) || (this.fsReindexed
+        .size() > 0));
+  }
+}

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/IntVector.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/IntVector.java?rev=1537789&r1=1537788&r2=1537789&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/IntVector.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/internal/util/IntVector.java Fri Nov  1 00:53:32 2013
@@ -20,6 +20,7 @@
 package org.apache.uima.internal.util;
 
 import java.io.Serializable;
+import java.util.Arrays;
 
 /**
  * Like {@link java.util.Vector java.util.Vector}, but elements are <code>int</code>s. This is a
@@ -309,6 +310,39 @@ public class IntVector implements Serial
     trimToSize();
     return this.array;
   }
+  
+  /**
+   * 
+   * @return an updated value for this vector, with the values sorted and duplicates removed
+   */
+  public IntVector sortDedup() {
+    Arrays.sort(array, 0, pos);
+    int prev = array[0];
+    int cpyfromIndex = 1;
+    int cpytoIndex = 1; 
+    
+    // go past first part of array until find first duplicate
+    for (; cpyfromIndex < pos; cpyfromIndex ++) {
+      final int v = array[cpyfromIndex];
+      if (v == prev) {
+        break;
+      }
+      prev = v;
+    }
+
+    // copyfromIndex == 1 past end or the index of first duplicate
+    cpytoIndex = cpyfromIndex ++;  
+    
+    for (; cpyfromIndex < pos; ) {
+      final int v = array[cpyfromIndex++];
+      if (v == prev) {
+        continue;
+      }
+      array[cpytoIndex++] = prev = v;
+    }
+    pos = cpytoIndex;
+    return this;
+  }
 
   /**
    * Return a copy of the underlying array.
@@ -397,4 +431,14 @@ public class IntVector implements Serial
     }
     return sum;
   }
+  // testing
+//  public static void main(String[] args) {
+//    IntVector iv = new IntVector();
+//    iv.add(new int[] {5, 3, 2, 7, 5, 3, 4, 5, 6, 5, 9, 8, 7});
+//    iv.sortDedup();
+//    for (int i = 0; i < iv.size(); i++) {
+//      System.out.print(iv.get(i) + " ");
+//    }
+//  }
+ 
 }

Modified: uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCasDeserializerTest.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCasDeserializerTest.java?rev=1537789&r1=1537788&r2=1537789&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCasDeserializerTest.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCasDeserializerTest.java Fri Nov  1 00:53:32 2013
@@ -44,6 +44,7 @@ import org.apache.uima.cas.ArrayFS;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
 import org.apache.uima.cas.FSIndex;
+import org.apache.uima.cas.FSIndexRepository;
 import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.FeatureStructure;
@@ -58,6 +59,7 @@ import org.apache.uima.cas.text.Annotati
 import org.apache.uima.cas_data.impl.CasComparer;
 import org.apache.uima.internal.util.XmlAttribute;
 import org.apache.uima.internal.util.XmlElementNameAndContents;
+import org.apache.uima.jcas.tcas.Annotation;
 import org.apache.uima.resource.metadata.FsIndexDescription;
 import org.apache.uima.resource.metadata.TypeDescription;
 import org.apache.uima.resource.metadata.TypeSystemDescription;
@@ -96,8 +98,11 @@ public class XmiCasDeserializerTest exte
     File typeSystemFile = JUnitExtension.getFile("ExampleCas/testTypeSystem.xml");
     File indexesFile = JUnitExtension.getFile("ExampleCas/testIndexes.xml");
 
+    // large type system
     typeSystem = UIMAFramework.getXMLParser().parseTypeSystemDescription(
             new XMLInputSource(typeSystemFile));
+    
+    // bag index for Entities and Relations
     indexes = UIMAFramework.getXMLParser().parseFsIndexCollection(new XMLInputSource(indexesFile))
             .getFsIndexes();
   }
@@ -192,6 +197,51 @@ public class XmiCasDeserializerTest exte
     xmlReader.parse(new InputSource(new StringReader(xml)));
   }
   
+  /**
+   * https://issues.apache.org/jira/browse/UIMA-3396
+   * @throws Exception
+   */
+  public void testDeltaCasIndexing() throws Exception {
+    try {
+      CAS cas1 = CasCreationUtils.createCas(typeSystem, new TypePriorities_impl(),
+              indexes);
+      CAS cas2 = CasCreationUtils.createCas(typeSystem, new TypePriorities_impl(),
+              indexes);
+      cas1.setDocumentText("This is a test document in the initial view");
+      FSIndexRepositoryImpl ir1 = (FSIndexRepositoryImpl) cas1.getIndexRepository();
+      
+      AnnotationFS anAnnotBefore = cas1.createAnnotation(cas1.getAnnotationType(), 0, 2);
+      ir1.addFS(anAnnotBefore);
+      
+      cas1.createMarker();  // will start journaling index updates
+      
+      AnnotationFS anAnnot1 = cas1.createAnnotation(cas1.getAnnotationType(), 0, 4);
+      ir1.addFS(anAnnot1);
+      ir1.removeFS(anAnnot1);
+      ir1.addFS(anAnnot1);
+      
+      assertTrue(ir1.getAddedFSs().length == 1);
+      assertTrue(ir1.getDeletedFSs().length == 0);
+      assertTrue(ir1.getReindexedFSs().length == 0);
+      
+      ir1.removeFS(anAnnotBefore);
+      ir1.addFS(anAnnotBefore);
+      
+      assertTrue(ir1.getAddedFSs().length == 1);
+      assertTrue(ir1.getDeletedFSs().length == 0);
+      assertTrue(ir1.getReindexedFSs().length == 1);      
+      
+      ir1.removeFS(anAnnotBefore);
+      assertTrue(ir1.getAddedFSs().length == 1);
+      assertTrue(ir1.getDeletedFSs().length == 1);
+      assertTrue(ir1.getReindexedFSs().length == 0);      
+
+      
+    } catch (Exception e) {
+    JUnitExtension.handleException(e);
+    }
+  }
+  
   public void testMultiThreadedSerialize() throws Exception {
     try {
       File tsWithNoMultiRefs = JUnitExtension.getFile("ExampleCas/testTypeSystem.xml");
@@ -959,7 +1009,7 @@ public class XmiCasDeserializerTest exte
       cas1.getIndexRepository().addFS(anAnnot1);
       AnnotationFS anAnnot2 = cas1.createAnnotation(cas1.getAnnotationType(), 5, 10);
       cas1.getIndexRepository().addFS(anAnnot2);
-      FSIndex tIndex = cas1.getAnnotationIndex();
+      FSIndex<AnnotationFS> tIndex = cas1.getAnnotationIndex();
       assertTrue(tIndex.size() == 3); //doc annot plus 2 annots
       
       //serialize complete  

Added: uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/internal/util/IntVectorTest.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/internal/util/IntVectorTest.java?rev=1537789&view=auto
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/internal/util/IntVectorTest.java (added)
+++ uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/internal/util/IntVectorTest.java Fri Nov  1 00:53:32 2013
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.uima.UIMAFramework;
+import org.apache.uima.analysis_engine.AnalysisEngine;
+import org.apache.uima.analysis_engine.AnalysisEngineDescription;
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.impl.UimaContext_ImplBase;
+import org.apache.uima.resource.CasManager;
+import org.apache.uima.test.junit_extension.JUnitExtension;
+import org.apache.uima.util.XMLInputSource;
+
+
+public class IntVectorTest extends TestCase {
+
+  public void testSortDedup() throws Exception {
+    IntVector iv = new IntVector();
+    iv.add(new int[] {5, 3, 2, 7, 5, 3, 4, 5, 6, 5, 9, 8, 7});
+    iv.sortDedup();
+    assertTrue(Arrays.equals(iv.toArray(), new int[] {2, 3, 4, 5, 6, 7, 8, 9}));    
+
+  }
+  
+  // verify that several CASes in a pool in different views share the same type system
+  
+  public void testPool() throws Exception {
+    try {
+      
+      AnalysisEngineDescription aed = (AnalysisEngineDescription)UIMAFramework.getXMLParser().parse(
+              new XMLInputSource(JUnitExtension
+                      .getFile("TextAnalysisEngineImplTest/TestPrimitiveTae1.xml")));
+      
+      AnalysisEngine ae = UIMAFramework.produceAnalysisEngine(aed);
+
+      // define a caspool of size 2
+      CasManager cm = ((UimaContext_ImplBase)ae.getUimaContext()).getResourceManager().getCasManager();
+      cm.defineCasPool("uniqueString", 2, null);
+      
+      CAS c1 = cm.getCas("uniqueString");
+      CAS c2 = cm.getCas("uniqueString");
+      c1.getJCas();
+      
+      CAS c1v2 = c1.createView("view2");
+      CAS c2v2 = c2.createView("view3");
+      c2v2.getJCas();
+      
+      TypeSystem ts = c1.getTypeSystem();
+      
+      Assert.assertTrue(ts == c2.getTypeSystem());
+      Assert.assertTrue(ts == c1v2.getTypeSystem());
+      Assert.assertTrue(ts == c2v2.getTypeSystem());
+
+    } catch (Exception e) {
+      JUnitExtension.handleException(e);
+    }
+  }
+
+}