Skip to main content
summaryrefslogblamecommitdiffstats
blob: ba8561908fd9d3d92edd848192bd649c0cfd32cc (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  
                                                                                 













                                                                        
                                                     












                                                           

                                                         









                                                                  













































                                                                                                      






                                                                 








                                                                  




                                  































































                                                                                                             

                           

                                                           















































































































                                                                                                


                                                           




                                             

                                                           





                                                                   
 


                                                                                          






                                            


                                        
       
                                               
       
                                                    


             
                      

















                                                                        
/*
 * Copyright (c) 2008-2013, 2015, 2016 Eike Stepper (Berlin, Germany) and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Simon McDuff - initial API and implementation
 *    Eike Stepper - maintenance
 */
package org.eclipse.emf.cdo.internal.server;

import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.util.CDOQueryInfo;
import org.eclipse.emf.cdo.common.util.CDOQueryQueue;
import org.eclipse.emf.cdo.internal.server.bundle.OM;
import org.eclipse.emf.cdo.server.IQueryContext;
import org.eclipse.emf.cdo.server.IQueryHandler;
import org.eclipse.emf.cdo.server.IRepository;
import org.eclipse.emf.cdo.server.IView;
import org.eclipse.emf.cdo.server.StoreThreadLocal;
import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil;
import org.eclipse.emf.cdo.spi.server.InternalQueryManager;
import org.eclipse.emf.cdo.spi.server.InternalQueryResult;
import org.eclipse.emf.cdo.spi.server.InternalRepository;
import org.eclipse.emf.cdo.spi.server.InternalSession;
import org.eclipse.emf.cdo.spi.server.InternalView;

import org.eclipse.net4j.util.concurrent.ConcurrencyUtil;
import org.eclipse.net4j.util.concurrent.ThreadPool;
import org.eclipse.net4j.util.container.IContainerDelta.Kind;
import org.eclipse.net4j.util.container.SingleDeltaContainerEvent;
import org.eclipse.net4j.util.event.IEvent;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.lifecycle.Lifecycle;
import org.eclipse.net4j.util.om.trace.ContextTracer;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

/**
 * @author Simon McDuff
 * @since 2.0
 */
public class QueryManager extends Lifecycle implements InternalQueryManager
{
  private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_SESSION, QueryManager.class);

  private InternalRepository repository;

  private Map<Integer, QueryContext> queryContexts = new ConcurrentHashMap<Integer, QueryContext>();

  private ExecutorService executors;

  private boolean shutdownExecutorService;

  private int nextQuery;

  private boolean allowInterruptRunningQueries = true;

  public QueryManager()
  {
  }

  public InternalRepository getRepository()
  {
    return repository;
  }

  public void setRepository(InternalRepository repository)
  {
    this.repository = repository;

    String value = repository.getProperties().get(IRepository.Props.ALLOW_INTERRUPT_RUNNING_QUERIES);
    if (value != null)
    {
      allowInterruptRunningQueries = Boolean.parseBoolean(value);
    }
  }

  public synchronized ExecutorService getExecutors()
  {
    if (executors == null)
    {
      executors = ConcurrencyUtil.getExecutorService(repository);

      if (executors == null)
      {
        shutdownExecutorService = true;
        executors = ThreadPool.create();
      }
    }

    return executors;
  }

  public synchronized void setExecutors(ExecutorService executors)
  {
    if (shutdownExecutorService)
    {
      if (this.executors != null)
      {
        this.executors.shutdown();
      }

      shutdownExecutorService = false;
    }

    this.executors = executors;
  }

  public InternalQueryResult execute(InternalView view, CDOQueryInfo queryInfo)
  {
    InternalQueryResult queryResult = new QueryResult(view, queryInfo, getNextQueryID());
    QueryContext queryContext = new QueryContext(queryResult);
    execute(queryContext);
    return queryResult;
  }

  public boolean isRunning(int queryID)
  {
    QueryContext queryContext = queryContexts.get(queryID);
    return queryContext != null;
  }

  public void cancel(int queryID)
  {
    QueryContext queryContext = queryContexts.get(queryID);
    if (queryContext == null || queryContext.getFuture().isDone())
    {
      throw new RuntimeException("Query " + queryID + " is not running anymore"); //$NON-NLS-1$ //$NON-NLS-2$
    }

    if (TRACER.isEnabled())
    {
      TRACER.trace("Cancelling query for context: " + queryContext); //$NON-NLS-1$
    }

    queryContext.cancel();
  }

  public synchronized void register(QueryContext queryContext)
  {
    int queryID = queryContext.getQueryResult().getQueryID();
    queryContexts.put(queryID, queryContext);
    queryContext.addListener();
  }

  public synchronized void unregister(QueryContext queryContext)
  {
    int queryID = queryContext.getQueryResult().getQueryID();
    queryContexts.remove(queryID);
    queryContext.removeListener();
  }

  public synchronized int getNextQueryID()
  {
    return ++nextQuery;
  }

  @Override
  protected void doDeactivate() throws Exception
  {
    super.doDeactivate();
    setExecutors(null);
  }

  private Future<?> execute(QueryContext queryContext)
  {
    register(queryContext);

    Future<?> future = getExecutors().submit(queryContext);
    queryContext.setFuture(future);
    return future;
  }

  /**
   * @author Simon McDuff
   * @since 2.0
   */
  private class QueryContext implements IQueryContext, Runnable
  {
    private CDOBranchPoint branchPoint;

    private InternalQueryResult queryResult;

    private boolean started;

    private boolean cancelled;

    private int resultCount;

    private Future<?> future;

    private IListener sessionListener = new IListener()
    {
      public void notifyEvent(IEvent event)
      {
        if (event instanceof SingleDeltaContainerEvent<?>)
        {
          IView view = getQueryResult().getView();
          SingleDeltaContainerEvent<?> deltaEvent = (SingleDeltaContainerEvent<?>)event;
          if (deltaEvent.getDeltaKind() == Kind.REMOVED && deltaEvent.getDeltaElement() == view)
          {
            // Cancel the query when view is closing
            cancel();
          }
        }
      }
    };

    public QueryContext(InternalQueryResult queryResult)
    {
      this.queryResult = queryResult;

      // Remember the branchPoint because it can change
      InternalView view = getView();

      // long timeStamp = view.getTimeStamp();
      // if (timeStamp == CDOBranchPoint.UNSPECIFIED_DATE && repository.isSupportingAudits())
      // {
      // timeStamp = repository.getTimeStamp();
      // }
      //
      // branchPoint = view.getBranch().getPoint(timeStamp);

      branchPoint = CDOBranchUtil.copyBranchPoint(view);
    }

    public InternalQueryResult getQueryResult()
    {
      return queryResult;
    }

    public InternalView getView()
    {
      return queryResult.getView();
    }

    public CDOBranch getBranch()
    {
      return branchPoint.getBranch();
    }

    public long getTimeStamp()
    {
      return branchPoint.getTimeStamp();
    }

    public Future<?> getFuture()
    {
      return future;
    }

    public void setFuture(Future<?> future)
    {
      this.future = future;
    }

    public void cancel()
    {
      cancelled = true;
      if (future != null)
      {
        future.cancel(allowInterruptRunningQueries);
      }

      if (!started)
      {
        unregister(this);
      }
    }

    public int getResultCount()
    {
      return resultCount;
    }

    public boolean addResult(Object object)
    {
      if (resultCount == 0)
      {
        throw new IllegalStateException("Maximum number of results exceeded"); //$NON-NLS-1$
      }

      CDOQueryQueue<Object> queue = queryResult.getQueue();
      queue.add(object);

      return !cancelled && --resultCount > 0;
    }

    public void run()
    {
      CDOQueryQueue<Object> queue = queryResult.getQueue();

      InternalSession session = queryResult.getView().getSession();
      StoreThreadLocal.setSession(session);

      try
      {
        started = true;

        CDOQueryInfo info = queryResult.getQueryInfo();
        resultCount = info.getMaxResults() < 0 ? Integer.MAX_VALUE : info.getMaxResults();
        IQueryHandler handler = repository.getQueryHandler(info);

        try
        {
          handler.executeQuery(info, this);
        }
        catch (Throwable executionException)
        {
          addResult(executionException);
          return;
        }
      }
      catch (Throwable initializationException)
      {
        queue.setException(initializationException);
      }
      finally
      {
        queue.close();
        unregister(this);
        StoreThreadLocal.release();
      }
    }

    public void addListener()
    {
      InternalSession session = getQueryResult().getView().getSession();
      session.addListener(sessionListener);
    }

    public void removeListener()
    {
      InternalSession session = getQueryResult().getView().getSession();
      session.removeListener(sessionListener);
    }
  }
}

Back to the top