/******************************************************************************* * Copyright (c) 2018 Association for Decentralized Information Management * in Industry THTH ry. * 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: * Semantum Oy - initial API and implementation *******************************************************************************/ package org.simantics.db.impl; import org.simantics.db.AsyncReadGraph; import org.simantics.db.exception.DatabaseException; import org.simantics.db.impl.graph.BarrierTracing; import org.simantics.db.impl.graph.ReadGraphImpl; import org.simantics.db.impl.query.AsyncReadEntry; import org.simantics.db.impl.query.PendingTaskSupport; import org.simantics.db.procedure.AsyncProcedure; import org.simantics.db.request.AsyncRead; public class BlockingAsyncProcedure implements AsyncProcedure, Runnable { private static final Object NO_RESULT = new Object(); private final Object key; private final ReadGraphImpl queryGraph; private final ReadGraphImpl callerGraph; private final AsyncReadEntry entry; private final AsyncProcedure procedure; private PendingTaskSupport pendingTaskSupport; private final boolean needsToBlock; private Object result = NO_RESULT; private Throwable exception = null; public BlockingAsyncProcedure(ReadGraphImpl callerGraph, AsyncReadEntry entry, AsyncProcedure procedure, Object key, boolean needsToBlock) { // A new graph for evaluating the query with correct parent and asyncBarrier queryGraph = callerGraph.withParent(entry, this, needsToBlock); queryGraph.asyncBarrier.inc(); // This makes sure that caller does not quit before dispatch callerGraph.asyncBarrier.inc(); this.entry = entry; this.procedure = procedure; this.key = key; this.queryGraph.asyncBarrier.inc(); this.callerGraph = callerGraph; this.needsToBlock = needsToBlock; if (BarrierTracing.BOOKKEEPING) { BarrierTracing.registerBAP(this); } } @Override public void execute(AsyncReadGraph graph_, Result result) { this.result = result; queryGraph.asyncBarrier.dec(); } @Override public void exception(AsyncReadGraph graph_, Throwable t) { this.exception = t; queryGraph.asyncBarrier.dec(); } public void waitBarrier() { queryGraph.asyncBarrier.waitBarrier(key, queryGraph); } public void dec() { queryGraph.asyncBarrier.dec(); } @SuppressWarnings("unchecked") public Result get() throws DatabaseException { if(needsToBlock) queryGraph.asyncBarrier.waitBarrier(key, queryGraph); if(exception != null) { if(exception instanceof DatabaseException) throw (DatabaseException)exception; throw new DatabaseException(exception); } else { return (Result)result; } } @SuppressWarnings("unchecked") public Result getResult() { return (Result)result; } public Throwable getException() { return exception; } @Override public String toString() { return "." + procedure; } @Override public void run() { AsyncProcedure procedure__ = entry != null ? entry : procedure; ReadGraphImpl executeGraph = callerGraph.withParent(callerGraph.parent, null, needsToBlock); executeGraph.asyncBarrier.inc(); // This counters the inc in the constructor callerGraph.asyncBarrier.dec(); try { if(procedure__ != null) { procedure__.execute(executeGraph, get()); } } catch (DatabaseException e) { if(procedure__ != null) procedure__.exception(executeGraph, e); exception = e; } catch (Throwable t) { DatabaseException dbe = new DatabaseException(t); if(procedure__ != null) procedure__.exception(executeGraph, dbe); exception = dbe; } finally { if (entry != null) { assert(entry.isReady()); // This does not throw entry.performFromCache(executeGraph, procedure); } executeGraph.asyncBarrier.dec(); if(needsToBlock) executeGraph.asyncBarrier.waitBarrier(procedure__, executeGraph); } if (BarrierTracing.BOOKKEEPING) { BarrierTracing.unregisterBAP(this); } } public void print() { System.err.println("BlockingAsyncProcedure"); System.err.println("-key: " + key); System.err.println("-queryGraph: " + queryGraph); System.err.println("-callerGraph: " + callerGraph); System.err.println("-procedure: " + procedure); System.err.println("-pendingTaskSupport: " + pendingTaskSupport); System.err.println("-result: " + result); System.err.println("-exception: " + exception); } public Result performSync(AsyncRead request) throws DatabaseException { try { request.perform(queryGraph, this); } finally { dec(); } return get(); } public void performAsync(AsyncRead request) throws DatabaseException { try { request.perform(queryGraph, this); } finally { dec(); } } }