public LeftTuple propagateModifyChildLeftTuple(
      LeftTuple childLeftTuple,
      RightTuple parentRightTuple,
      PropagationContext context,
      InternalWorkingMemory workingMemory,
      boolean tupleMemoryEnabled) {
    // iterate to find all child tuples for the shared node
    while (childLeftTuple != null && childLeftTuple.getRightParent() == parentRightTuple) {
      // this will iterate for each child node when the
      // the current node is shared

      // preserve the current LeftTuple, as we need to iterate to the next before re-adding
      LeftTuple temp = childLeftTuple;
      childLeftTuple.getLeftTupleSink().modifyLeftTuple(childLeftTuple, context, workingMemory);
      childLeftTuple = childLeftTuple.getLeftParentNext();
      temp.reAddRight();
    }
    return childLeftTuple;
  }
Example #2
0
  public void modifyLeftTuple(
      LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) {
    final AccumulateMemory memory = (AccumulateMemory) workingMemory.getNodeMemory(this);
    final AccumulateContext accctx = (AccumulateContext) leftTuple.getObject();

    BetaMemory bm = memory.betaMemory;

    // Add and remove to make sure we are in the right bucket and at the end
    // this is needed to fix for indexing and deterministic iteration
    bm.getLeftTupleMemory().removeAdd(leftTuple);

    this.constraints.updateFromTuple(bm.getContext(), workingMemory, leftTuple);
    LeftTuple childLeftTuple = getFirstMatch(leftTuple, accctx, false);

    RightTupleMemory rightMemory = bm.getRightTupleMemory();

    FastIterator rightIt = getRightIterator(rightMemory);

    RightTuple rightTuple = getFirstRightTuple(leftTuple, rightMemory, context, rightIt);

    // first check our index (for indexed nodes only) hasn't changed and we are returning the same
    // bucket
    // if rightTuple is null, we assume there was a bucket change and that bucket is empty
    if (childLeftTuple != null
        && rightMemory.isIndexed()
        && !rightIt.isFullIterator()
        && (rightTuple == null
            || (rightTuple.getMemory() != childLeftTuple.getRightParent().getMemory()))) {
      // our index has changed, so delete all the previous matchings
      removePreviousMatchesForLeftTuple(leftTuple, workingMemory, memory, accctx);

      childLeftTuple = null; // null so the next check will attempt matches for new bucket
    }

    // we can't do anything if RightTupleMemory is empty
    if (rightTuple != null) {
      if (childLeftTuple == null) {
        // either we are indexed and changed buckets or
        // we had no children before, but there is a bucket to potentially match, so try as normal
        // assert
        for (; rightTuple != null; rightTuple = (RightTuple) rightIt.next(rightTuple)) {
          final InternalFactHandle handle = rightTuple.getFactHandle();
          if (this.constraints.isAllowedCachedLeft(bm.getContext(), handle)) {
            // add a new match
            addMatch(leftTuple, rightTuple, null, null, workingMemory, memory, accctx, true);
          }
        }
      } else {
        boolean isDirty = false;
        // in the same bucket, so iterate and compare
        for (; rightTuple != null; rightTuple = (RightTuple) rightIt.next(rightTuple)) {
          final InternalFactHandle handle = rightTuple.getFactHandle();

          if (this.constraints.isAllowedCachedLeft(bm.getContext(), handle)) {
            if (childLeftTuple == null || childLeftTuple.getRightParent() != rightTuple) {
              // add a new match
              addMatch(
                  leftTuple, rightTuple, childLeftTuple, null, workingMemory, memory, accctx, true);
            } else {
              // we must re-add this to ensure deterministic iteration
              LeftTuple temp = childLeftTuple.getLeftParentNext();
              childLeftTuple.reAddRight();
              childLeftTuple = temp;
            }
          } else if (childLeftTuple != null && childLeftTuple.getRightParent() == rightTuple) {
            LeftTuple temp = childLeftTuple.getLeftParentNext();
            // remove the match
            removeMatch(rightTuple, childLeftTuple, workingMemory, memory, accctx, false);
            childLeftTuple = temp;
            // the next line means that when a match is removed from the current leftTuple
            // and the accumulate does not support the reverse operation, then the whole
            // result is dirty (since removeMatch above is not recalculating the total)
            // and we need to do this later
            isDirty = !accumulate.supportsReverse();
          }
          // else do nothing, was false before and false now.
        }
        if (isDirty) {
          reaccumulateForLeftTuple(leftTuple, workingMemory, memory, accctx);
        }
      }
    }

    this.constraints.resetTuple(memory.betaMemory.getContext());
    if (accctx.getAction() == null) {
      evaluateResultConstraints(
          ActivitySource.LEFT, leftTuple, context, workingMemory, memory, accctx, true);
    } // else evaluation is already scheduled, so do nothing
  }