Package org.apache.openjpa.slice.jdbc

Source Code of org.apache.openjpa.slice.jdbc.DistributedSQLStoreQuery$ParallelExecutor

/*
* 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.openjpa.slice.jdbc;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.kernel.SQLStoreQuery;
import org.apache.openjpa.kernel.FetchConfiguration;
import org.apache.openjpa.kernel.OrderingMergedResultObjectProvider;
import org.apache.openjpa.kernel.QueryContext;
import org.apache.openjpa.kernel.StoreManager;
import org.apache.openjpa.kernel.StoreQuery;
import org.apache.openjpa.lib.rop.MergedResultObjectProvider;
import org.apache.openjpa.lib.rop.RangeResultObjectProvider;
import org.apache.openjpa.lib.rop.ResultObjectProvider;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.slice.DistributedConfiguration;
import org.apache.openjpa.slice.SliceThread;
import org.apache.openjpa.util.StoreException;

/**
* A query for distributed databases.
*
* @author Pinaki Poddar
*
*/
@SuppressWarnings("serial")
class DistributedSQLStoreQuery extends SQLStoreQuery {
  private List<StoreQuery> _queries = new ArrayList<StoreQuery>();

  public DistributedSQLStoreQuery(JDBCStore store) {
    super(store);
  }

  void add(StoreQuery q) {
    _queries.add(q);
  }

  public DistributedJDBCStoreManager getDistributedStore() {
    return (DistributedJDBCStoreManager) getStore();
  }

  public Executor newDataStoreExecutor(ClassMetaData meta, boolean subs) {
    boolean parallel = !getContext().getStoreContext().getBroker()
      .getMultithreaded();
        ParallelExecutor ex = new ParallelExecutor(this, meta, parallel);
    for (StoreQuery q : _queries) {
      ex.addExecutor(q.newDataStoreExecutor(meta, subs));
    }
    return ex;
  }

  public void setContext(QueryContext ctx) {
    super.setContext(ctx);
    for (StoreQuery q : _queries)
      q.setContext(ctx);
  }

  /**
   * Executes queries on multiple databases.
   *
   * @author Pinaki Poddar
   *
   */
  public static class ParallelExecutor extends
      SQLStoreQuery.SQLExecutor {
    private List<Executor> executors = new ArrayList<Executor>();
    private DistributedSQLStoreQuery owner = null;

        public ParallelExecutor(DistributedSQLStoreQuery dsq, ClassMetaData meta, boolean p) {
      super(dsq, meta);
      owner = dsq;
    }

    public void addExecutor(Executor ex) {
      executors.add(ex);
    }

    /**
         * Each child query must be executed with slice context and not the
     * given query context.
     */
    public ResultObjectProvider executeQuery(StoreQuery q,
        final Object[] params, final Range range) {
      List<Future<ResultObjectProvider>> futures =
        new ArrayList<Future<ResultObjectProvider>>();
            final List<Executor> usedExecutors = new ArrayList<Executor>();
      final List<ResultObjectProvider> rops =
        new ArrayList<ResultObjectProvider>();
      List<SliceStoreManager> targets = findTargets();
      QueryContext ctx = q.getContext();
      boolean isReplicated = containsReplicated(ctx);
            ExecutorService threadPool = SliceThread.getPool();
      for (int i = 0; i < owner._queries.size(); i++) {
                // if replicated, then execute only on single slice
        if (isReplicated && !usedExecutors.isEmpty()) {
          break;
        }
                StoreManager sm = owner.getDistributedStore().getSlice(i);
        if (!targets.contains(sm))
          continue;
        StoreQuery query = owner._queries.get(i);
        Executor executor = executors.get(i);
        if (!targets.contains(sm))
          continue;
        usedExecutors.add(executor);
                QueryExecutor call = new QueryExecutor();
                call.executor = executor;
                call.query = query;
                call.params = params;
                call.range = range;
                futures.add(threadPool.submit(call));
      }
      for (Future<ResultObjectProvider> future : futures) {
        try {
          rops.add(future.get());
        } catch (InterruptedException e) {
          throw new RuntimeException(e);
        } catch (ExecutionException e) {
          throw new StoreException(e.getCause());
        }
      }
     
      ResultObjectProvider[] tmp = rops
                    .toArray(new ResultObjectProvider[rops.size()]);
      ResultObjectProvider result = null;
      boolean[] ascending = getAscending(q);
      boolean isAscending = ascending.length > 0;
      boolean isAggregate = ctx.isAggregate();
      boolean hasRange = ctx.getEndRange() != Long.MAX_VALUE;
      if (isAggregate) {
        result = new UniqueResultObjectProvider(tmp, q,
            getQueryExpressions());
      } else if (isAscending) {
                result = new OrderingMergedResultObjectProvider(tmp, ascending,
                    usedExecutors.toArray(new Executor[usedExecutors.size()]),
          q, params);
      } else {
        result = new MergedResultObjectProvider(tmp);
      }
      if (hasRange) {
                result = new RangeResultObjectProvider(result,
                        ctx.getStartRange(), ctx.getEndRange());
      }
      return result;
    }

    /**
         * Scans metadata to find out if a replicated class is the candidate.
     */
    boolean containsReplicated(QueryContext query) {
      Class<?> candidate = query.getCandidateType();
      DistributedConfiguration conf = (DistributedConfiguration)query.getStoreContext()
          .getConfiguration();
      if (candidate != null) {
          return conf.isReplicated(candidate);
      }
      ClassMetaData[] metas = query.getAccessPathMetaDatas();
      if (metas == null || metas.length < 1)
        return false;
      for (ClassMetaData meta : metas)
        if (conf.isReplicated(meta.getDescribedType()))
          return true;
      return false;
    }

    public Number executeDelete(StoreQuery q, Object[] params) {
      Iterator<StoreQuery> qs = owner._queries.iterator();
      List<Future<Number>> futures = null;
      int result = 0;
            ExecutorService threadPool = SliceThread.getPool();
      for (Executor ex : executors) {
        if (futures == null)
                    futures = new ArrayList<Future<Number>>();
        DeleteExecutor call = new DeleteExecutor();
        call.executor = ex;
        call.query = qs.next();
        call.params = params;
        futures.add(threadPool.submit(call));
      }
      for (Future<Number> future : futures) {
        try {
          Number n = future.get();
          if (n != null)
            result += n.intValue();
        } catch (InterruptedException e) {
          throw new RuntimeException(e);
        } catch (ExecutionException e) {
          throw new StoreException(e.getCause());
        }
      }
      return result;
    }

    public Number executeUpdate(StoreQuery q, Object[] params) {
      Iterator<StoreQuery> qs = owner._queries.iterator();
      List<Future<Number>> futures = null;
      int result = 0;
            ExecutorService threadPool = SliceThread.getPool();
      for (Executor ex : executors) {
        if (futures == null)
                    futures = new ArrayList<Future<Number>>();
        UpdateExecutor call = new UpdateExecutor();
        call.executor = ex;
        call.query = qs.next();
        call.params = params;
        futures.add(threadPool.submit(call));
      }
      for (Future<Number> future : futures) {
        try {
          Number n = future.get();
                    result += (n == null) ? 0 : n.intValue();
        } catch (InterruptedException e) {
          throw new RuntimeException(e);
        } catch (ExecutionException e) {
          throw new StoreException(e.getCause());
        }
      }
      return result;
    }

    List<SliceStoreManager> findTargets() {
      FetchConfiguration fetch = owner.getContext()
          .getFetchConfiguration();
      return owner.getDistributedStore().getTargets(fetch);
    }
   
  }

  static class QueryExecutor implements Callable<ResultObjectProvider> {
    StoreQuery query;
    Executor executor;
    Object[] params;
    Range range;

    public ResultObjectProvider call() throws Exception {
      return executor.executeQuery(query, params, range);
    }
  }

  static class DeleteExecutor implements Callable<Number> {
    StoreQuery query;
    Executor executor;
    Object[] params;

    public Number call() throws Exception {
      return executor.executeDelete(query, params);
    }
  }

  static class UpdateExecutor implements Callable<Number> {
    StoreQuery query;
    Executor executor;
    Object[] params;

    public Number call() throws Exception {
        return executor.executeUpdate(query, params);
    }
  }
}
TOP

Related Classes of org.apache.openjpa.slice.jdbc.DistributedSQLStoreQuery$ParallelExecutor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.