示例#1
0
  /**
   * Constructs the element iff requested, saves the rule reference iff requested, and clones and
   * saves the bindingSet iff requested. The requested behavior depends on {@link
   * IJoinNexus#solutionFlags()}. When requested, the element is created using {@link
   * IRelation#newElement(IPredicate, IBindingSet)} for the {@link IRelation} that is named by the
   * head of the rule.
   *
   * @param e The element.
   * @param rule The rule.
   * @param bindingSet The binding set for this solution. If {@link IJoinNexus#BINDINGS} was
   *     specified, then the binding set will be <em>cloned</em> by this ctor.
   * @throws IllegalArgumentException if any parameter is <code>null</code>.
   */
  @SuppressWarnings("unchecked")
  public Solution(final IJoinNexus joinNexus, final IRule<E> rule, final IBindingSet bindingSet) {

    if (joinNexus == null) throw new IllegalArgumentException();

    if (rule == null) throw new IllegalArgumentException();

    if (bindingSet == null) throw new IllegalArgumentException();

    final int flags = joinNexus.solutionFlags();

    if ((flags & IJoinNexus.ELEMENT) != 0) {

      /*
       * The relation is responsible for how the elements are materialized
       * from the bindings.
       *
       * Note: Caching for this relation is very important!
       */

      // the head of the rule.
      final IPredicate head = rule.getHead();

      // the relation for the head of the rule.
      final IRelation relation = joinNexus.getHeadRelationView(head);

      // use the relation's element factory.
      this.e =
          (E) relation.newElement(head.args(), bindingSet); // TODO BOp.args() is not efficient!

      //            // use the relation's element factory.
      //            this.e = (E) relation.newElement(head, bindingSet);

    } else {

      this.e = null;
    }

    if ((flags & IJoinNexus.BINDINGS) != 0) {

      this.bindingSet = bindingSet.clone();

    } else {

      this.bindingSet = null;
    }

    if ((flags & IJoinNexus.RULE) != 0) {

      this.rule = rule;

    } else {

      this.rule = null;
    }
  }
示例#2
0
  /**
   * The head relation is what we write on for mutation operations and is also responsible for
   * minting new elements from computed {@link ISolution}s. This method depends solely on the name
   * of the head relation and the timestamp of interest for the view.
   */
  public IRelation getHeadRelationView(final IPredicate pred) {

    if (pred.getRelationCount() != 1) throw new IllegalArgumentException();

    final String relationName = pred.getOnlyRelationName();

    final long timestamp =
        (getAction().isMutation() ? getWriteTimestamp() : getReadTimestamp(/*relationName*/ ));

    return (IRelation<?>) resourceLocator.locate(relationName, timestamp);
  }
示例#3
0
  public Iterator<PartitionLocator> locatorScan(
      final AbstractScaleOutFederation<?> fed, final IPredicate<?> predicate) {

    final long timestamp = getReadTimestamp();

    // Note: assumes that we are NOT using a view of two relations.
    final IRelation<?> relation =
        (IRelation<?>) fed.getResourceLocator().locate(predicate.getOnlyRelationName(), timestamp);

    /*
     * Find the best access path for the predicate for that relation.
     *
     * Note: All we really want is the [fromKey] and [toKey] for that
     * predicate and index. This MUST NOT layer on expanders since the
     * layering also hides the [fromKey] and [toKey].
     */
    @SuppressWarnings("unchecked")
    final AccessPath<?> accessPath = (AccessPath<?>) relation.getAccessPath((IPredicate) predicate);

    // Note: assumes scale-out (EDS or JDS).
    final IClientIndex ndx = (IClientIndex) accessPath.getIndex();

    /*
     * Note: could also be formed from relationName + "." +
     * keyOrder.getIndexName(), which is cheaper unless the index metadata
     * is cached.
     */
    final String name = ndx.getIndexMetadata().getName();

    return fed.locatorScan(
        name, timestamp, accessPath.getFromKey(), accessPath.getToKey(), false /* reverse */);
  }
示例#4
0
  @SuppressWarnings("unchecked")
  private final void copyValues(
      final IElement e, final IPredicate<?> pred, final IBindingSet bindingSet) {

    for (int i = 0; i < pred.arity(); i++) {

      final IVariableOrConstant<?> t = pred.get(i);

      if (t.isVar()) {

        final IVariable<?> var = (IVariable<?>) t;

        final Constant<?> newval = new Constant(e.get(i));

        bindingSet.set(var, newval);
      }
    }
  }
示例#5
0
  @SuppressWarnings("unchecked")
  public IRelation getTailRelationView(final IPredicate pred) {

    final int nsources = pred.getRelationCount();

    if (nsources == 1) {

      return (IRelation) resourceLocator.locate(pred.getOnlyRelationName(), getReadTimestamp());

    } else if (nsources == 2) {

      final IRelation<?> relation0 =
          (IRelation) resourceLocator.locate(pred.getRelationName(0), readTimestamp);

      final IRelation<?> relation1 =
          (IRelation) resourceLocator.locate(pred.getRelationName(1), readTimestamp);

      return new RelationFusedView(relation0, relation1).init();

    } else {

      throw new UnsupportedOperationException();
    }
  }
示例#6
0
    /** Do a hash join of the buffered solutions with the access path. */
    private void doHashJoin() {

      if (state.isEmpty()) return;

      final IBindingSetAccessPath<?> accessPath = getAccessPath();

      if (log.isInfoEnabled()) log.info("accessPath=" + accessPath);

      stats.accessPathCount.increment();

      stats.accessPathRangeCount.add(accessPath.rangeCount(false /* exact */));

      final UnsyncLocalOutputBuffer<IBindingSet> unsyncBuffer =
          new UnsyncLocalOutputBuffer<IBindingSet>(op.getChunkCapacity(), sink);

      final long cutoffLimit =
          pred.getProperty(
              IPredicate.Annotations.CUTOFF_LIMIT, IPredicate.Annotations.DEFAULT_CUTOFF_LIMIT);

      // Obtain the iterator for the current join dimension.
      final ICloseableIterator<IBindingSet[]> itr = accessPath.solutions(cutoffLimit, stats);

      /*
       * Note: The [stats] are NOT passed in here since the chunksIn and
       * unitsIn were updated when the pipeline solutions were accepted
       * into the hash index. If we passed in stats here, they would be
       * double counted when we executed the hash join against the access
       * path.
       */
      state.hashJoin(
          itr, // left
          null, // stats
          unsyncBuffer // out
          );

      switch (state.getJoinType()) {
        case Normal:
          /*
           * Nothing to do.
           */
          break;
        case Optional:
        case NotExists:
          {
            /*
             * Output the optional solutions.
             */

            // where to write the optional solutions.
            final AbstractUnsynchronizedArrayBuffer<IBindingSet> unsyncBuffer2 =
                sink2 == null
                    ? unsyncBuffer
                    : new UnsyncLocalOutputBuffer<IBindingSet>(op.getChunkCapacity(), sink2);

            state.outputOptionals(unsyncBuffer2);

            unsyncBuffer2.flush();
            if (sink2 != null) sink2.flush();

            break;
          }
        case Exists:
          {
            /*
             * Output the join set.
             */
            state.outputJoinSet(unsyncBuffer);
            break;
          }
        default:
          throw new AssertionError();
      }

      unsyncBuffer.flush();
      sink.flush();
    }