예제 #1
0
 /** Calculates the accumulated PRE value shifts for all updates on the list. */
 private void accumulatePreValueShifts() {
   if (!dirty) return;
   int s = 0;
   for (int i = updStructural.size() - 1; i >= 0; i--) {
     final BasicUpdate t = updStructural.get(i);
     s += t.shifts;
     t.accumulatedShifts = s;
   }
   dirty = false;
 }
예제 #2
0
  /**
   * Resolves unwanted text node adjacency which can result from structural changes in the database.
   * Adjacent text nodes are two text nodes A and B, where PRE(B)=PRE(A)+1 and PARENT(A)=PARENT(B).
   */
  private void resolveTextAdjacency() {
    // Text node merges are also gathered on a separate list to leverage optimizations.
    final AtomicUpdateList allMerges = new AtomicUpdateList(data);

    // keep track of the visited locations to avoid superfluous checks
    final IntSet s = new IntSet();
    // Text nodes have to be merged from the highest to the lowest pre value
    for (int i = 0; i < updStructural.size(); i++) {
      final BasicUpdate u = updStructural.get(i);
      final Data insseq = u.getInsertionData();
      // calculate the new location of the update, here we have to check for adjacency
      final int newLocation = u.location + u.accumulatedShifts - u.shifts;
      final int beforeNewLocation = newLocation - 1;
      // check surroundings of this location for adjacent text nodes depending on the
      // kind of update, first the one with higher PRE values (due to shifts!)
      // ... for insert/replace ...
      if (insseq != null) {
        // calculate the current following node
        final int followingNode = newLocation + insseq.meta.size;
        final int beforeFollowingNode = followingNode - 1;
        // check the nodes at the end of/after the insertion sequence
        if (!s.contains(beforeFollowingNode)) {
          final AtomicUpdateList merges = necessaryMerges(beforeFollowingNode, allMerges.data);
          mergeNodes(merges);
          allMerges.merge(merges);
          s.add(beforeFollowingNode);
        }
      }
      // check nodes for delete and for insert before the updated location
      if (!s.contains(beforeNewLocation)) {
        final AtomicUpdateList merges = necessaryMerges(beforeNewLocation, allMerges.data);
        mergeNodes(merges);
        allMerges.merge(merges);
        s.add(beforeNewLocation);
      }
    }

    allMerges.updateDistances();
    allMerges.clear();
  }
예제 #3
0
  /**
   * Checks the list of updates for violations. Updates must be ordered strictly from the highest to
   * the lowest PRE value.
   *
   * <p>A single node must not be affected by more than one {@link Rename}, {@link UpdateValue}
   * operation.
   *
   * <p>A single node must not be affected by more than one destructive operation. These operations
   * include {@link Replace}, {@link Delete}.
   */
  public void check() {
    if (ok || updStructural.size() < 2 && updValue.size() < 2) return;

    int i = 0;
    while (i + 1 < updStructural.size()) {
      final BasicUpdate current = updStructural.get(i);
      final BasicUpdate next = updStructural.get(++i);

      // check order of location PRE
      if (current.location < next.location)
        Util.notexpected("Invalid order at location " + current.location);

      if (current.location == next.location) {
        // check multiple {@link Delete}, {@link Replace}
        if (current.destructive() && next.destructive())
          Util.notexpected("Multiple deletes/replaces on node " + current.location);
      }
    }

    i = 0;
    while (i + 1 < updValue.size()) {
      final BasicUpdate current = updValue.get(i++);
      final BasicUpdate next = updValue.get(i);

      // check order of location PRE
      if (current.location < next.location)
        Util.notexpected("Invalid order at location " + current.location);

      if (current.location == next.location) {
        // check multiple {@link Rename}
        if (current instanceof Rename && next instanceof Rename)
          Util.notexpected("Multiple renames on node " + current.location);

        // check multiple {@link UpdateValue}
        if (current instanceof UpdateValue && next instanceof UpdateValue)
          Util.notexpected("Multiple updates on node " + current.location);
      }
    }
    ok = true;
  }
예제 #4
0
  /**
   * Removes superfluous update operations. If a node T is deleted or replaced, all updates on the
   * descendant axis of T can be left out as they won't affect the database after all.
   *
   * <p>Superfluous updates can have a minimum PRE value of pre(T)+1 and a maximum PRE value of
   * pre(T)+size(T).
   *
   * <p>An update with location pre(T)+size(T) can only be removed if the update is an atomic insert
   * and the inserted node is then part of the subtree of T.
   */
  public void optimize() {
    if (opt) return;

    check();
    // traverse from lowest to highest PRE value
    int i = updStructural.size() - 1;
    while (i >= 0) {
      final BasicUpdate u = updStructural.get(i);
      // If this update can lead to superfluous updates ...
      if (u.destructive()) {
        // we determine the lowest and highest PRE values of a superfluous update
        final int pre = u.location;
        final int fol = pre + data.size(pre, data.kind(pre));
        i--;
        // and have a look at the next candidate
        while (i >= 0) {
          final BasicUpdate desc = updStructural.get(i);
          final int descpre = desc.location;
          // if the candidate operates on the subtree of T and inserts a node ...
          if (descpre <= fol
              && (desc instanceof Insert || desc instanceof InsertAttr)
              && desc.parent() >= pre
              && desc.parent() < fol) {
            // it is removed.
            updStructural.remove(i--);

            // Other updates (not inserting a node) that operate on the subtree of T can
            // only have a PRE value that is smaller than the following PRE of T
          } else if (descpre < fol) {
            // these we delete.
            updStructural.remove(i--);

            // Else there's nothing to delete
          } else break;
        }
      } else i--;
    }
    opt = true;
  }
예제 #5
0
 /** Carries out value updates. */
 public void applyValueUpdates() {
   for (final BasicUpdate t : updValue) t.apply(data);
 }
예제 #6
0
 /** Carries out structural updates. */
 public void applyStructuralUpdates() {
   accumulatePreValueShifts();
   for (final BasicUpdate t : updStructural) t.apply(data);
 }