/* * Copyright (c) 2012, 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: * Eike Stepper - initial API and implementation */ package org.eclipse.emf.cdo.server.internal.lissome.optimizer; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionCache; import org.eclipse.emf.cdo.common.revision.CDORevisionCacheAdder; import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; import org.eclipse.emf.cdo.eresource.EresourcePackage; import org.eclipse.emf.cdo.server.IStoreAccessor; import org.eclipse.emf.cdo.server.IStoreAccessor.QueryResourcesContext; import org.eclipse.emf.cdo.server.internal.lissome.LissomeStore; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionCache; import org.eclipse.net4j.util.ObjectUtil; import org.eclipse.net4j.util.concurrent.Worker; import org.eclipse.net4j.util.io.IORuntimeException; import org.eclipse.net4j.util.lifecycle.Lifecycle; import org.eclipse.emf.ecore.EClass; import java.io.IOException; import java.util.LinkedList; /** * @author Eike Stepper */ public class Optimizer extends Lifecycle { private final LissomeStore store; private final boolean async; private final LinkedList<OptimizerTask> queue = new LinkedList<OptimizerTask>(); private Worker worker; private Cache cache; public Optimizer(LissomeStore store, boolean async) { this.store = store; this.async = async; } public LissomeStore getStore() { return store; } public boolean isAsync() { return async; } public OptimizerTask[] getTasks() { return getCache().getTasks(); } public void addTask(OptimizerTask task) { synchronized (queue) { cache = null; queue.addLast(task); queue.notifyAll(); } if (!async) { try { executeFirstTask(); } catch (InterruptedException ignore) { // Can not happen } } } protected void executeFirstTask() throws InterruptedException { try { OptimizerTask task = getFirstTask(); task.execute(this); removeFirstTask(); } catch (InterruptedException ex) { throw ex; } catch (IOException ex) { throw new IORuntimeException(ex); } } protected OptimizerTask getFirstTask() throws InterruptedException { OptimizerTask task; synchronized (queue) { while (queue.isEmpty()) { queue.wait(100); } task = queue.getFirst(); } return task; } protected void removeFirstTask() { synchronized (queue) { cache = null; queue.removeFirst(); queue.notifyAll(); } } @Override protected void doActivate() throws Exception { super.doActivate(); if (async) { worker = new TaskWorker(); worker.activate(); } } @Override protected void doDeactivate() throws Exception { synchronized (queue) { while (!queue.isEmpty()) { queue.wait(100); } } if (async) { worker.deactivate(); worker = null; } super.doDeactivate(); } protected Cache getCache() { synchronized (queue) { if (cache == null) { boolean supportingBranches = store.getRepository().isSupportingBranches(); cache = new Cache(queue, supportingBranches); } return cache; } } public boolean queryResources(IStoreAccessor.QueryResourcesContext context) { Cache cache = getCache(); return cache.queryResources(context); } public InternalCDORevision readRevision(CDOID id, CDOBranchPoint branchPoint) { Cache cache = getCache(); return cache.readRevision(id, branchPoint); } public void handleRevisions(EClass eClass, CDOBranch branch, long timeStamp, boolean exactTime, CDORevisionHandler handler) { // TODO: implement Optimizer.handleRevisions(eClass, branch, timeStamp, exactTime, handler) } /** * @author Eike Stepper */ private final class TaskWorker extends Worker { @Override protected String getThreadName() { return "OptimizerTaskWorker"; } @Override protected void work(WorkContext context) throws Exception { executeFirstTask(); } } /** * @author Eike Stepper */ private static final class Cache { private final OptimizerTask[] tasks; private final boolean supportingBranches; private CDORevisionCache revisionCache; public Cache(LinkedList<OptimizerTask> queue, boolean supportingBranches) { this.supportingBranches = supportingBranches; tasks = queue.toArray(new OptimizerTask[queue.size()]); } public OptimizerTask[] getTasks() { return tasks; } public synchronized CDORevisionCache getRevisionCache() { if (revisionCache == null) { revisionCache = CDORevisionUtil.createRevisionCache(true, supportingBranches); CDORevisionCacheAdder adder = new CDORevisionCacheAdder() { public void addRevision(CDORevision revision) { reviseOldRevision(revision); revisionCache.addRevision(revision); } private void reviseOldRevision(CDORevision revision) { int version = revision.getVersion(); if (version > CDOBranchVersion.FIRST_VERSION) { CDOID id = revision.getID(); CDOBranchVersion oldVersion = revision.getBranch().getVersion(version - 1); InternalCDORevision oldRevision = (InternalCDORevision)revisionCache.getRevisionByVersion(id, oldVersion); if (oldRevision != null) { oldRevision.setRevised(revision.getTimeStamp() - 1); } } } }; for (OptimizerTask task : tasks) { if (task instanceof CommitTransactionTask) { CommitTransactionTask commitTask = (CommitTransactionTask)task; commitTask.cacheRevisions(adder); } } } return revisionCache; } public boolean queryResources(QueryResourcesContext context) { InternalCDORevisionCache revisionCache = (InternalCDORevisionCache)getRevisionCache(); for (CDORevision revision : revisionCache.getRevisions(context)) { if (!revision.isResourceNode()) { continue; } CDOID folderID = (CDOID)revision.data().getContainerID(); if (!ObjectUtil.equals(folderID, context.getFolderID())) { continue; } String name = context.getName(); String revisionName = (String)revision.data().get(EresourcePackage.Literals.CDO_RESOURCE_NODE__NAME, 0); boolean useEquals = context.exactMatch() || revisionName == null || name == null; boolean match = useEquals ? ObjectUtil.equals(revisionName, name) : revisionName.startsWith(name); if (!match) { continue; } if (!context.addResource(revision.getID())) { // No more results allowed return false; } } return true; } public InternalCDORevision readRevision(CDOID id, CDOBranchPoint branchPoint) { CDORevisionCache revisionCache = getRevisionCache(); return (InternalCDORevision)revisionCache.getRevision(id, branchPoint); } } }