/** * diqube: Distributed Query Base. * * Copyright (C) 2015 Bastian Gloeckle * * This file is part of diqube. * * diqube is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.diqube.threads; import java.io.ByteArrayOutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.util.List; import java.util.UUID; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A {@link ThreadPoolExecutor} that is aware of the diql Query it is running for. * * @author Bastian Gloeckle */ /* package */class DiqubeFixedThreadPoolExecutor extends ThreadPoolExecutor { private static final Logger logger = LoggerFactory.getLogger(DiqubeFixedThreadPoolExecutor.class); private UUID queryUuid; private UUID executionUuid; private int numberOfThreads; private String nameFormat; public DiqubeFixedThreadPoolExecutor(int numberOfThreads, ThreadFactory threadFactory, UUID queryUuid, UUID executionUuid) { super(numberOfThreads, numberOfThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); this.numberOfThreads = numberOfThreads; this.queryUuid = queryUuid; this.executionUuid = executionUuid; } public UUID getQueryUuid() { return queryUuid; } public UUID getExecutionUuid() { return executionUuid; } /* package */void setThreadNameFormatForToString(String nameFormat) { this.nameFormat = nameFormat; } @Override public String toString() { return this.getClass().getSimpleName() + "[threads=" + numberOfThreads + ",queryUuid=" + queryUuid + ",executionUuid=" + executionUuid + ",nameFormat=" + ((nameFormat == null) ? "null" : nameFormat) + "]"; } @Override public List<Runnable> shutdownNow() { if (logger.isTraceEnabled() && this.getActiveCount() > 0) { try { // Log current stack trace - when trace is enabled and we will kill some threads, we want to know who did this! RuntimeException e = new RuntimeException(); ByteArrayOutputStream stackTraceStream = new ByteArrayOutputStream(); PrintWriter writer = new PrintWriter(new OutputStreamWriter(stackTraceStream, "UTF-8")); e.printStackTrace(writer); writer.flush(); String stackTrace = stackTraceStream.toString("UTF-8"); logger.trace("Interrupting one executor of query {}, execution {}, stacktrace: {}", queryUuid, executionUuid, stackTrace); } catch (UnsupportedEncodingException e) { logger.trace("Unable to log stack trace of interruption", e); } } return super.shutdownNow(); } }