All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bigdata.relation.rule.eval.AbstractJoinNexus Maven / Gradle / Ivy

/**

Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016.  All rights reserved.

Contact:
     SYSTAP, LLC DBA Blazegraph
     2501 Calvert ST NW #106
     Washington, DC 20008
     [email protected]

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
/*
 * Created on Aug 20, 2010
 */

package com.bigdata.relation.rule.eval;

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

import com.bigdata.bop.Constant;
import com.bigdata.bop.IBindingSet;
import com.bigdata.bop.IConstant;
import com.bigdata.bop.IConstraint;
import com.bigdata.bop.IElement;
import com.bigdata.bop.IPredicate;
import com.bigdata.bop.IVariable;
import com.bigdata.bop.IVariableOrConstant;
import com.bigdata.bop.bindingSet.ListBindingSet;
import com.bigdata.bop.joinGraph.DefaultRangeCountFactory;
import com.bigdata.bop.joinGraph.IEvaluationPlanFactory;
import com.bigdata.bop.joinGraph.IRangeCountFactory;
import com.bigdata.btree.keys.DelegateSortKeyBuilder;
import com.bigdata.btree.keys.ISortKeyBuilder;
import com.bigdata.config.Configuration;
import com.bigdata.config.IValidator;
import com.bigdata.config.IntegerValidator;
import com.bigdata.config.LongValidator;
import com.bigdata.io.IStreamSerializer;
import com.bigdata.io.SerializerUtil;
import com.bigdata.journal.IIndexManager;
import com.bigdata.journal.Journal;
import com.bigdata.journal.TemporaryStore;
import com.bigdata.mdi.PartitionLocator;
import com.bigdata.relation.AbstractResource;
import com.bigdata.relation.IMutableRelation;
import com.bigdata.relation.IRelation;
import com.bigdata.relation.RelationFusedView;
import com.bigdata.relation.accesspath.AccessPath;
import com.bigdata.relation.accesspath.BlockingBuffer;
import com.bigdata.relation.accesspath.IAccessPath;
import com.bigdata.relation.accesspath.IBlockingBuffer;
import com.bigdata.relation.accesspath.IBuffer;
import com.bigdata.relation.accesspath.IElementFilter;
import com.bigdata.relation.accesspath.UnsynchronizedArrayBuffer;
import com.bigdata.relation.locator.IResourceLocator;
import com.bigdata.relation.rule.IProgram;
import com.bigdata.relation.rule.IRule;
import com.bigdata.relation.rule.IStep;
import com.bigdata.service.AbstractScaleOutFederation;
import com.bigdata.service.DataService;
import com.bigdata.service.IBigdataFederation;
import com.bigdata.service.ndx.IClientIndex;
import com.bigdata.striterator.ChunkedConvertingIterator;
import com.bigdata.striterator.DistinctFilter;
import com.bigdata.striterator.IChunkedOrderedIterator;

/**
 * Base implementation for {@link IJoinNexus}
 * 
 * @author Bryan Thompson
 * @version $Id$
 */
abstract public class AbstractJoinNexus implements IJoinNexus {

    private final static transient Logger log = Logger.getLogger(AbstractJoinNexus.class);
    
    private final IJoinNexusFactory joinNexusFactory;
    
    protected final IIndexManager indexManager;
    
    /** Note: cached. */
    protected final IResourceLocator resourceLocator;

    private final ActionEnum action;
    
    private final long writeTimestamp;
    
    protected final long readTimestamp;

    protected final int chunkCapacity;
    protected final int chunkOfChunksCapacity;
    private final boolean forceSerialExecution;
    private final int maxParallelSubqueries;
    private final int fullyBufferedReadThreshold;
    private final long chunkTimeout;

    /**
     * The {@link TimeUnit}s in which the {@link #chunkTimeout} is measured.
     */
    private static final TimeUnit chunkTimeoutUnit = TimeUnit.MILLISECONDS;

    final public int getChunkOfChunksCapacity() {

        return chunkOfChunksCapacity;
        
    }

    final public int getChunkCapacity() {

        return chunkCapacity;
        
    }
    
    final public int getFullyBufferedReadThreshold() {
        
        return fullyBufferedReadThreshold;
        
    }

    final public String getProperty(final String name, final String defaultValue) {

        // @todo pass namespace in with the IJoinNexusFactory?
        return Configuration.getProperty(indexManager,
                joinNexusFactory.getProperties(), null/* namespace */, name,
                defaultValue);

    }

    final public  T getProperty(final String name, final String defaultValue,
            final IValidator validator) {

        // @todo pass namespace in with the IJoinNexusFactory?
        return Configuration.getProperty(indexManager,
                joinNexusFactory.getProperties(), null/* namespace */, name,
                defaultValue, validator);

    }

    protected final int solutionFlags;
    
    protected final IElementFilter filter;

    public IElementFilter getSolutionFilter() {
        
        return filter == null ? null : new SolutionFilter(filter);
        
    }

    /**
     * The factory for rule evaluation plans.
     */
    protected final IEvaluationPlanFactory planFactory;

    /**
     * @todo caching for the same relation and database state shared across join
     *       nexus instances.
     */
    private final IRangeCountFactory rangeCountFactory = new DefaultRangeCountFactory(
            this);

    private final IRuleStatisticsFactory ruleStatisticsFactory = new IRuleStatisticsFactory() {

        public RuleStats newInstance(IStep step) {
            
            return new RuleStats(step);
            
        }

        public RuleStats newInstance(IRuleState ruleState) {
         
            return new RuleStats(ruleState);

        }
        
    };
    
    /**
     * @param joinNexusFactory
     *            The object used to create this instance and which can be used
     *            to create other instances as necessary for distributed rule
     *            execution.
     * @param indexManager
     *            The object used to resolve indices, relations, etc.
     */
    protected AbstractJoinNexus(final IJoinNexusFactory joinNexusFactory,
            final IIndexManager indexManager) {

        if (joinNexusFactory == null)
            throw new IllegalArgumentException();
        
        if (indexManager == null)
            throw new IllegalArgumentException();

        this.joinNexusFactory = joinNexusFactory;
        
        this.indexManager = indexManager;
        
        this.resourceLocator = indexManager.getResourceLocator();
        
        this.action = joinNexusFactory.getAction();
        
        this.writeTimestamp = joinNexusFactory.getWriteTimestamp();

        this.readTimestamp = joinNexusFactory.getReadTimestamp();
        
        forceSerialExecution = Boolean.parseBoolean(getProperty(
                AbstractResource.Options.FORCE_SERIAL_EXECUTION,
                AbstractResource.Options.DEFAULT_FORCE_SERIAL_EXECUTION));

        maxParallelSubqueries = getProperty(
                AbstractResource.Options.MAX_PARALLEL_SUBQUERIES,
                AbstractResource.Options.DEFAULT_MAX_PARALLEL_SUBQUERIES,
                IntegerValidator.GTE_ZERO);

        chunkOfChunksCapacity = getProperty(
                AbstractResource.Options.CHUNK_OF_CHUNKS_CAPACITY,
                AbstractResource.Options.DEFAULT_CHUNK_OF_CHUNKS_CAPACITY,
                IntegerValidator.GT_ZERO);

        chunkCapacity = getProperty(AbstractResource.Options.CHUNK_CAPACITY,
                AbstractResource.Options.DEFAULT_CHUNK_CAPACITY,
                IntegerValidator.GT_ZERO);

        chunkTimeout = getProperty(AbstractResource.Options.CHUNK_TIMEOUT,
                AbstractResource.Options.DEFAULT_CHUNK_TIMEOUT,
                LongValidator.GTE_ZERO);

        fullyBufferedReadThreshold = getProperty(
                AbstractResource.Options.FULLY_BUFFERED_READ_THRESHOLD,
                AbstractResource.Options.DEFAULT_FULLY_BUFFERED_READ_THRESHOLD,
                IntegerValidator.GT_ZERO);

        this.solutionFlags = joinNexusFactory.getSolutionFlags();

        this.filter = joinNexusFactory.getSolutionFilter();
        
        this.planFactory = joinNexusFactory.getEvaluationPlanFactory();
   
    }

    public IRuleStatisticsFactory getRuleStatisticsFactory() {
        
        return ruleStatisticsFactory;
        
    }

    public IJoinNexusFactory getJoinNexusFactory() {
        
        return joinNexusFactory;
        
    }
    
    public IRangeCountFactory getRangeCountFactory() {
        
        return rangeCountFactory;
        
    }
    
    final public boolean forceSerialExecution() {

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

        return forceSerialExecution;
        
    }
    
    final public int getMaxParallelSubqueries() {
        
        return maxParallelSubqueries;
        
    }
    
    final public ActionEnum getAction() {
        
        return action;
        
    }
    
    final public long getWriteTimestamp() {

        return writeTimestamp;

    }

    final public long getReadTimestamp() {
        
        return readTimestamp;
        
    }

    /**
     * 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);

    }

    @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();

        }

    }

//    /**
//     * @deprecated by {@link #getTailAccessPath(IRelation, IPredicate)}
//     * 
//     * @see #getTailAccessPath(IRelation, IPredicate).
//     */
//    public IAccessPath getTailAccessPath(final IPredicate predicate) {
//     
//        // Resolve the relation name to the IRelation object.
//        final IRelation relation = getTailRelationView(predicate);
//
//        return getTailAccessPath(relation, predicate);
//
//    }

    public IAccessPath getTailAccessPath(final IRelation relation,
            final IPredicate predicate) {

        return relation.getAccessPath(indexManager/* localIndexManager */,
                relation.getKeyOrder(predicate), predicate); 
        
//        if (predicate.getPartitionId() != -1) {
//
//            /*
//             * Note: This handles a read against a local index partition. For
//             * scale-out, the [indexManager] will be the data service's local
//             * index manager.
//             * 
//             * Note: Expanders ARE NOT applied in this code path. Expanders
//             * require a total view of the relation, which is not available
//             * during scale-out pipeline joins. Likewise, the [backchain]
//             * property will be ignored since it is handled by an expander.
//             */
//
//            return ((AbstractRelation) relation)
//                    .getAccessPathForIndexPartition(indexManager, predicate);
//
//        }
//
//        // Find the best access path for the predicate for that relation.
//        final IAccessPath accessPath = relation.getAccessPath(predicate);
//        
//        // Note: No expander's for bops, at least not right now.
////        final ISolutionExpander expander = predicate.getSolutionExpander();
////        
////        if (expander != null) {
////            
////            // allow the predicate to wrap the access path
////            accessPath = expander.getAccessPath(accessPath);
////            
////        }
//        
//        // return that access path.
//        return accessPath;
    }

    public Iterator 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 */);

    }
    
    final public IIndexManager getIndexManager() {
        
        return indexManager;
        
    }

    @SuppressWarnings("unchecked")
    final public boolean bind(final IRule rule, final int index,
            final Object e, final IBindingSet bindings) {

        // propagate bindings from the visited object into the binding set.
        copyValues((IElement) e, rule.getTail(index), bindings);

        // verify constraints.
        return rule.isConsistent(bindings);

    }

    final public boolean bind(final IPredicate pred,
            final IConstraint[] constraints, final Object e,
            final IBindingSet bindings) {

        // propagate bindings from the visited object into the binding set.
        copyValues((IElement) e, pred, bindings);

        if (constraints != null) {

            // verify constraint.
            return isConsistent(constraints, bindings);
        
        }
        
        // no constraint.
        return true;
        
    }
    
    /**
     * Check constraints.
     * 
     * @param constraints
     * @param bindingSet
     * 
     * @return true iff the constraints are satisfied.
     */
    private boolean isConsistent(final IConstraint[] constraints,
            final IBindingSet bindingSet) {

        for (int i = 0; i < constraints.length; i++) {

            final IConstraint constraint = constraints[i];

            if (!constraint.accept(bindingSet)) {

                if (log.isDebugEnabled()) {

                    log.debug("Rejected by "
                            + constraint.getClass().getSimpleName() + " : "
                            + bindingSet);

                }

                return false;

            }

        }

        return true;

    }
    
    @SuppressWarnings("unchecked")
    final private 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);

            }

        }

    }

    final public ISolution newSolution(final IRule rule,
            final IBindingSet bindingSet) {

        final Solution solution = new Solution(this, rule, bindingSet);

        if (log.isDebugEnabled()) {

            log.debug(solution.toString());

        }

        return solution;

    }

    final public int solutionFlags() {

        return solutionFlags;

    }

    /**
     * FIXME Custom serialization for solution sets, especially since there
     * tends to be a lot of redundancy in the data arising from how bindings are
     * propagated during JOINs.
     * 
     * @todo We can sort the {@link ISolution}s much like we already do for
     *       DISTINCT or intend to do for SORT and use the equivalent of leading
     *       key compression to reduce IO costs (or when they are SORTed we
     *       could leverage that to produce a more compact serialization).
     * 
     * @see SPOSolutionSerializer (needs to be written).
     */
    public IStreamSerializer getSolutionSerializer() {
        
        return SerializerUtil.STREAMS;
        
    }

    /**
     * FIXME Custom serialization for binding sets, especially since there tends
     * to be a lot of redundancy in the data arising from how bindings are
     * propagated during JOINs.
     * 
     * @todo We can sort the {@link ISolution}s much like we already do for
     *       DISTINCT or intend to do for SORT and use the equivalent of leading
     *       key compression to reduce IO costs (or when they are SORTed we
     *       could leverage that to produce a more compact serialization).
     * 
     * @see SPOBindingSetSerializer, which has not been finished.
     */
    public IStreamSerializer getBindingSetSerializer() {
        
        return SerializerUtil.STREAMS;
        
    }

    final public IBindingSet newBindingSet(final IRule rule) {

        final IBindingSet constants = rule.getConstants();

        final int nconstants = constants.size();
        
        final IBindingSet bindingSet =
                new ListBindingSet()
//                new ArrayBindingSet(rule.getVariableCount()+ nconstants)
        ;

        if (nconstants > 0) {
        
            /*
             * Bind constants declared by the rule before returning the binding
             * set to the caller.
             */
            
            final Iterator> itr = constants
                    .iterator();
            
            while(itr.hasNext()) {
                
                final Map.Entry entry = itr.next();
                
                bindingSet.set(entry.getKey(), entry.getValue());
                
            }
            
        }
        
        return bindingSet;
        
    }

    final public IRuleTaskFactory getRuleTaskFactory(final boolean parallel,
            final IRule rule) {

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

        // is there a task factory override?
        IRuleTaskFactory taskFactory = rule.getTaskFactory();

        if (taskFactory == null) {

            // no, use the default factory.
            taskFactory = joinNexusFactory.getDefaultRuleTaskFactory();

        }
        
        /*
         * Note: Now handled by the MutationTask itself.
         */
//        if (getAction().isMutation() && (!parallel || forceSerialExecution())) {
//
//            /*
//             * Tasks for sequential mutation steps are always wrapped to ensure
//             * that the thread-safe buffer is flushed onto the mutable relation
//             * after each rule executes. This is necessary in order for the
//             * results of one rule in a sequential program to be visible to the
//             * next rule in that sequential program.
//             */
//            
//            taskFactory = new RunRuleAndFlushBufferTaskFactory(taskFactory);
//
//        }

        return taskFactory;

    }

    final public IEvaluationPlanFactory getPlanFactory() {
        
        return planFactory;
        
    }
    
    final public IResourceLocator getRelationLocator() {
        
        return resourceLocator;
        
    }

    final public IBuffer newUnsynchronizedBuffer(
            final IBuffer targetBuffer, final int chunkCapacity) {

        // MAY be null.
        final IElementFilter filter = getSolutionFilter();
        
        return new UnsynchronizedArrayBuffer(targetBuffer,
                chunkCapacity, ISolution.class, filter);
        
    }
    
    /**
     * Note: {@link ISolution} (not relation elements) will be written on the
     * buffer concurrently by different rules so there is no natural order for
     * the elements in the buffer.
     */
    final public IBlockingBuffer newQueryBuffer() {

        if (getAction().isMutation())
            throw new IllegalStateException();
        
        return new BlockingBuffer(chunkOfChunksCapacity,
                chunkCapacity, chunkTimeout, chunkTimeoutUnit);
        
    }
    
    /**
     * {@inheritDoc}
     * 

* Note: {@link #getSolutionFilter()} is applied by * {@link #newUnsynchronizedBuffer(IBuffer, int)} and NOT by the buffer * returned by this method. */ @SuppressWarnings("unchecked") public IBuffer newInsertBuffer(final IMutableRelation relation) { if (getAction() != ActionEnum.Insert) throw new IllegalStateException(); if (log.isDebugEnabled()) { log.debug("relation=" + relation); } /* * Buffer resolves the computed elements and writes them on the * statement indices. */ return new AbstractSolutionBuffer.InsertSolutionBuffer( chunkOfChunksCapacity, relation); } /** * {@inheritDoc} *

* Note: {@link #getSolutionFilter()} is applied by * {@link #newUnsynchronizedBuffer(IBuffer, int)} and NOT by the buffer * returned by this method. */ @SuppressWarnings("unchecked") public IBuffer newDeleteBuffer(final IMutableRelation relation) { if (getAction() != ActionEnum.Delete) throw new IllegalStateException(); if (log.isDebugEnabled()) { log.debug("relation=" + relation); } return new AbstractSolutionBuffer.DeleteSolutionBuffer( chunkOfChunksCapacity, relation); } /** * Return the {@link ISortKeyBuilder} used to impose DISTINCT on the * solutions generated by a query. * * @param head * The head of the rule. * * @return The {@link ISortKeyBuilder}. * * @todo This should be based on bop annotations and a hash table for * distinct unless it is very high volume and you can wait for the * first result, in which case a SORT should be selected. For high * volume with low latency to the first result, use a persistent hash * table on a temporary store. */ abstract protected ISortKeyBuilder newSortKeyBuilder( final IPredicate head); @SuppressWarnings("unchecked") public IChunkedOrderedIterator runQuery(final IStep step) throws Exception { if (step == null) throw new IllegalArgumentException(); if(log.isInfoEnabled()) log.info("program="+step.getName()); if(isEmptyProgram(step)) { log.warn("Empty program"); return (IChunkedOrderedIterator) new EmptyProgramTask( ActionEnum.Query, step).call(); } final IChunkedOrderedIterator itr = (IChunkedOrderedIterator) runProgram( ActionEnum.Query, step); if (step.isRule() && ((IRule) step).getQueryOptions().isDistinct()) { /* * Impose a DISTINCT constraint based on the variable bindings * selected by the head of the rule. The DistinctFilter will be * backed by a TemporaryStore if more than one chunk of solutions is * generated. That TemporaryStore will exist on the client where * this method (runQuery) was executed. The TemporaryStore will be * finalized and deleted when it is no longer referenced. */ final ISortKeyBuilder sortKeyBuilder; if (((IRule) step).getHead() != null && (solutionFlags & ELEMENT) != 0) { /* * Head exists and elements are requested, so impose DISTINCT * based on the materialized elements. */ sortKeyBuilder = new DelegateSortKeyBuilder( newSortKeyBuilder(((IRule) step).getHead())) { protected Object resolve(Object solution) { return ((ISolution) solution).get(); } }; } else { if ((solutionFlags & BINDINGS) != 0) { /* * Bindings were requested so impose DISTINCT based on those * bindings. */ sortKeyBuilder = new DelegateSortKeyBuilder( newBindingSetSortKeyBuilder((IRule) step)) { protected IBindingSet resolve(ISolution solution) { return solution.getBindingSet(); } }; } else { throw new UnsupportedOperationException( "You must specify BINDINGS since the rule does not have a head: " + step); } } return new ChunkedConvertingIterator(itr, new DistinctFilter(indexManager) { protected byte[] getSortKey(ISolution e) { return sortKeyBuilder.getSortKey(e); } }); } return itr; } final public long runMutation(final IStep step) throws Exception { if (step == null) throw new IllegalArgumentException(); if (!action.isMutation()) throw new IllegalStateException(); if (step.isRule() && ((IRule) step).getHead() == null) { throw new IllegalArgumentException("No head for this rule: " + step); } if(log.isInfoEnabled()) log.info("action=" + action + ", program=" + step.getName()); if(isEmptyProgram(step)) { log.warn("Empty program"); return (Long) new EmptyProgramTask(action, step).call(); } return (Long) runProgram(action, step); } /** * Return true iff the step is an empty {@link IProgram}. * * @param step * The step. */ final protected boolean isEmptyProgram(final IStep step) { if (!step.isRule() && ((IProgram) step).stepCount() == 0) { return true; } return false; } /** * Core impl. This handles the logic required to execute the program either * on a target {@link DataService} (highly efficient) or within the client * using the {@link IClientIndex} to submit operations to the appropriate * {@link DataService}(s) (not very efficient, even w/o RMI). * * @return Either an {@link IChunkedOrderedIterator} (query) or {@link Long} * (mutation count). */ final protected Object runProgram(final ActionEnum action, final IStep step) throws Exception { if (action == null) throw new IllegalArgumentException(); if (step == null) throw new IllegalArgumentException(); final IIndexManager indexManager = getIndexManager(); if (indexManager instanceof IBigdataFederation) { // distributed program execution. return runDistributedProgram((IBigdataFederation) indexManager, action, step); } else { // local Journal or TemporaryStore execution. return runLocalProgram(action, step); } } /** * This variant handles both local indices on a {@link TemporaryStore} or * {@link Journal} WITHOUT concurrency controls (fast). */ final protected Object runLocalProgram(final ActionEnum action, final IStep step) throws Exception { if (log.isInfoEnabled()) log.info("Running local program: action=" + action + ", program=" + step.getName()); final IProgramTask innerTask = new ProgramTask(action, step, getJoinNexusFactory(), getIndexManager()); return innerTask.call(); } /** * Runs a distributed {@link IProgram} (key-range partitioned indices, RMI, * and multi-machine). */ final protected Object runDistributedProgram(final IBigdataFederation fed, final ActionEnum action, final IStep step) throws Exception { if (log.isInfoEnabled()) { log.info("Running distributed program: action=" + action + ", program=" + step.getName()); } final IProgramTask innerTask = new ProgramTask(action, step, getJoinNexusFactory(), getIndexManager()); return innerTask.call(); } // /** // * This variant is submitted and executes the rules from inside of the // * {@link ConcurrencyManager} on the {@link LocalDataServiceImpl} (fast). // *

// * Note: This can only be done if all indices for the relation(s) are (a) // * unpartitioned; and (b) located on the SAME {@link DataService}. This is // * true for {@link LocalDataServiceFederation}. All other // * {@link IBigdataFederation} implementations are scale-out (use key-range // * partitioned indices). // */ // protected Object runDataServiceProgram(final DataService dataService, // final ActionEnum action, final IStep step) // throws InterruptedException, ExecutionException { // // if (log.isInfoEnabled()) { // // log.info("Submitting program to data service: action=" + action // + ", program=" + step.getName() + ", dataService=" // + dataService); // // } // // final IProgramTask innerTask = new ProgramTask(action, step, // getJoinNexusFactory()); // // return dataService.submit(innerTask).get(); // // } // /** // * Return true if the relationName is on a // * {@link TempTripleStore} // * // * @todo Rather than parsing the relation name, it would be better to have // * the temporary store UUIDs explicitly declared. // */ // protected boolean isTempStore(String relationName) { // // /* This is a typical UUID-based temporary store relation name. // * // * 1 2 3 // * 01234567890123456789012345678901234567 // * 81ad63b9-2172-45dc-bd97-03b63dfe0ba0kb.spo // */ // // if (relationName.length() > 37) { // // /* // * Could be a relation on a temporary store. // */ // if ( relationName.charAt( 8) == '-' // // && relationName.charAt(13) == '-' // // && relationName.charAt(18) == '-' // // && relationName.charAt(23) == '-' // // && relationName.charAt(38) == '.' // // ) { // // /* // * Pretty certain to be a relation on a temporary store. // */ // // return true; // // } // // } // // return false; // // } //// /** //// * A per-relation reentrant read-write lock allows either concurrent readers //// * or an writer on the unisolated view of a relation. When we use this lock //// * we also use {@link ITx#UNISOLATED} reads and writes and //// * {@link #makeWriteSetsVisible()} is a NOP. //// */ //// final private static boolean useReentrantReadWriteLockAndUnisolatedReads = true; // // public long getReadTimestamp(String relationName) { // //// if (useReentrantReadWriteLockAndUnisolatedReads) { // //// if (action.isMutation()) { //// //// assert readTimestamp == ITx.UNISOLATED : "readTimestamp="+readTimestamp; //// //// } // // return readTimestamp; // //// } else { //// //// /* //// * When the relation is the focusStore choose {@link ITx#UNISOLATED}. //// * Otherwise choose whatever was specified to the //// * {@link RDFJoinNexusFactory}. This is because we avoid doing a //// * commit on the focusStore and instead just its its UNISOLATED //// * indices. This is more efficient since they are already buffered //// * and since we can avoid touching disk at all for small data sets. //// */ //// //// if (isTempStore(relationName)) { //// //// return ITx.UNISOLATED; //// //// } //// //// if (lastCommitTime != 0L && action.isMutation()) { //// //// /* //// * Note: This advances the read-behind timestamp for a local //// * Journal configuration without the ConcurrencyManager (the //// * only scenario where we do an explicit commit). //// */ //// //// return TimestampUtility.asHistoricalRead(lastCommitTime); //// //// } //// //// return readTimestamp; //// //// } // // } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy