1 package org.simantics.db.common.utils;
3 import java.util.concurrent.Semaphore;
4 import java.util.concurrent.TimeUnit;
5 import java.util.concurrent.atomic.AtomicInteger;
7 import org.simantics.db.ReadGraph;
8 import org.simantics.db.Session;
10 import org.simantics.db.exception.DatabaseException;
11 import org.simantics.db.procedure.Procedure;
12 import org.simantics.db.request.Read;
15 * @author Tuukka Lehtonen
17 public final class RequestUtil {
19 private static final boolean TRACE_SCHEDULE = false;
20 private static final boolean TRACE_WAITED_TIME = false;
21 private static final boolean TRACE_TIMEOUT = false;
22 private static final boolean TRACE_RESULT_TIME = false;
24 static class ResultProcedure<R> extends Semaphore implements Procedure<R> {
26 private static final long serialVersionUID = 8645926264625496924L;
28 private static final Object NO_RESULT = new Object();
29 private Object resultOrException = NO_RESULT;
31 public ResultProcedure() {
36 public void execute(R result) {
37 resultOrException = result;
42 public void exception(Throwable t) {
43 resultOrException = t;
47 @SuppressWarnings("unchecked")
48 public R waitForResultOrException(long timeout, R timeoutResult) throws DatabaseException, InterruptedException {
49 long nt0 = System.nanoTime();
53 tryAcquire(timeout, TimeUnit.MILLISECONDS);
55 Object r = resultOrException;
56 if (TRACE_WAITED_TIME)
57 System.out.println("slept waiting for result for " + ((double) (System.nanoTime() - nt0) / 1e6) + " ms");
60 System.out.println("timed out (" + timeout + " ms) waiting for request result, returning default " + timeoutResult);
63 if (r instanceof Throwable) {
64 if (r instanceof DatabaseException)
65 throw (DatabaseException) r;
66 throw new DatabaseException((Throwable) r);
68 if (TRACE_RESULT_TIME)
69 System.out.println("got result in " + ((double) (System.nanoTime() - nt0) / 1e6) + " ms");
75 static class TimeoutingRequest<R> extends Semaphore implements Read<R> {
77 private static final long serialVersionUID = -5216095211800988013L;
79 Read<R> wrappedRequest;
80 Procedure<R> wrappedProcedure;
82 * 0 = not running, not timed out
86 AtomicInteger state = new AtomicInteger();
88 public TimeoutingRequest(Read<R> request, Procedure<R> procedure) {
90 this.wrappedRequest = request;
91 this.wrappedProcedure = procedure;
95 public R perform(ReadGraph graph) throws DatabaseException {
96 if (state.compareAndSet(0, 1)) {
98 return wrappedProcedure != null
99 ? graph.syncRequest(wrappedRequest, wrappedProcedure)
100 : graph.syncRequest(wrappedRequest);
103 System.out.println("[" + System.currentTimeMillis() + "] canceling execution of request " + wrappedRequest + ", startup timed out");
109 public boolean waitForRequestStart(long timeout) throws InterruptedException {
110 long nt0 = System.nanoTime();
111 tryAcquire(timeout, TimeUnit.MILLISECONDS);
112 if (TRACE_WAITED_TIME)
113 System.out.println("[" + wrappedRequest + "] request start wait time " + ((double) (System.nanoTime() - nt0) / 1e6) + " ms");
114 if (state.compareAndSet(0, 2)) {
116 System.out.println("[" + wrappedRequest + "] starting of request timed out (>= " + timeout + " ms)");
126 * database session handle
127 * @param requestStartTimeout
128 * timeout in milliseconds for the request execution to start. If
129 * request execution is not started within this period of time,
130 * timeoutResult<code>timeoutResult</code>requestExecutionTimeout
131 * will be returned. Must be ≥ 0.
132 * @param requestExecutionTimeout
133 * the maximum time to wait for the request execution to complete
134 * from the time the request execution was started. If negative,
135 * there is no timeout.
136 * @param timeoutResult
141 * @throws DatabaseException
142 * @throws InterruptedException
144 public static final <R> R trySyncRequest(
146 long requestStartTimeout,
147 long requestExecutionTimeout,
150 final Procedure<R> procedure)
151 throws DatabaseException, InterruptedException
153 if (requestStartTimeout < 0)
154 throw new IllegalArgumentException("request start timeout must be >= 0, got " + requestStartTimeout);
156 System.out.println("[" + read + "] scheduling timed request with timeouts " + requestStartTimeout + "/" + requestExecutionTimeout + " ms");
157 ResultProcedure<R> proc = new ResultProcedure<>();
158 TimeoutingRequest<R> req = new TimeoutingRequest<>(read, procedure);
159 session.asyncRequest(req, proc);
160 if (!req.waitForRequestStart(requestStartTimeout))
161 return timeoutResult;
162 return proc.waitForResultOrException(requestExecutionTimeout, timeoutResult);
165 public static final <R> R trySyncRequest(
167 long requestStartTimeout,
168 long requestExecutionTimeout,
170 Procedure<R> procedure)
171 throws DatabaseException, InterruptedException
173 return trySyncRequest(session, requestStartTimeout, requestExecutionTimeout, null, read, procedure);
176 public static final <R> R trySyncRequest(
178 long requestStartTimeout,
179 long requestExecutionTimeout,
182 throws DatabaseException, InterruptedException
184 return trySyncRequest(session, requestStartTimeout, requestExecutionTimeout, timeoutResult, read, null);
187 public static final <R> R trySyncRequest(
189 long requestStartTimeout,
190 long requestExecutionTimeout,
192 throws DatabaseException, InterruptedException
194 return trySyncRequest(session, requestStartTimeout, requestExecutionTimeout, null, read, null);