@Override public ScheduledFuture<?> schedule(final Runnable command, final long timeLimitMillis, final TimeUnit unit, final ScheduledExecutorService scheduledExecutorService, final DefaultQuery query) { final CacheRuntimeException lowMemoryException = createCancelationException(timeLimitMillis, query); query.setQueryCanceledException(lowMemoryException); throw lowMemoryException; }
private ScheduledFuture<?> scheduleCancelationTask(final DefaultQuery query, final long timeLimitMillis) { // Make ThreadLocal queryCanceled available to closure, which will run in a separate thread final AtomicBoolean queryCanceledThreadLocal = DefaultQuery.queryCanceled.get(); /* * This is where the GoF "State" design pattern comes home to roost. * * memoryState.schedule() is going to either schedule or throw an exception depending on what * state we are _currently_ in. Remember the switching of that state (reference) happens * in a separate thread, up in the setLowMemory() method, generally called by the * HeapMemoryMonitor. * * The first line of the lambda/closure, when it _eventually_ runs (in yet another thread-- * a thread from the executor), will access what is _then_ the current state, through * memoryState, to createCancelationException(). */ return memoryState.schedule(() -> { final CacheRuntimeException exception = memoryState .createCancelationException(timeLimitMillis, query); query.setQueryCanceledException(exception); queryCanceledThreadLocal.set(true); }, timeLimitMillis, TimeUnit.MILLISECONDS, executor, query); }
@Test public void monitorQueryThreadExpirationTaskScheduled() { DefaultQuery query = mock(DefaultQuery.class); monitor.monitorQueryThread(query); Mockito.verify(scheduledThreadPoolExecutor, times(1)).schedule(captor.capture(), anyLong(), isA(TimeUnit.class)); captor.getValue().run(); Mockito.verify(query, times(1)) .setQueryCanceledException(isA(QueryExecutionTimeoutException.class)); assertThatThrownBy(QueryMonitor::throwExceptionIfQueryOnCurrentThreadIsCanceled) .isExactlyInstanceOf(QueryExecutionCanceledException.class); }
String reason = "Query execution canceled due to low memory while gathering results from partitioned regions"; query.setQueryCanceledException(new QueryExecutionLowMemoryException(reason)); } else { if (logger.isDebugEnabled()) {
private void checkIfQueryShouldBeCancelled() { if (QueryMonitor.isLowMemory()) { String reason = "Query execution canceled due to low memory while gathering results from partitioned regions"; query.setQueryCanceledException(new QueryExecutionLowMemoryException(reason)); if (DefaultQuery.testHook != null) { DefaultQuery.testHook .doTestHook(DefaultQuery.TestHook.SPOTS.BEFORE_THROW_QUERY_CANCELED_EXCEPTION, null); } throw query.getQueryCanceledException(); } else if (query.isCanceled()) { throw query.getQueryCanceledException(); } }
String reason = "Query execution canceled due to low memory while gathering results from partitioned regions"; query.setQueryCanceledException(new QueryExecutionLowMemoryException(reason)); this.abort = true;