diff --git a/api/model/src/main/java/com/emc/mongoose/api/model/storage/StorageDriver.java b/api/model/src/main/java/com/emc/mongoose/api/model/storage/StorageDriver.java index 2cf4381702..d805cbf56d 100644 --- a/api/model/src/main/java/com/emc/mongoose/api/model/storage/StorageDriver.java +++ b/api/model/src/main/java/com/emc/mongoose/api/model/storage/StorageDriver.java @@ -60,4 +60,8 @@ boolean isIdle() void adjustIoBuffers(final long avgDataItemSize, final IoType ioType) throws RemoteException; + + @Override + void close() + throws IOException; } diff --git a/config/defaults.json b/config/defaults.json index 8dd43e83df..4ec115677f 100644 --- a/config/defaults.json +++ b/config/defaults.json @@ -261,7 +261,7 @@ // An user may place here a key-value pair which will be used as HTTP header. "headers" : { "Connection" : "Keep-Alive", - "User-Agent" : "mongoose/3.5.0" + "User-Agent" : "mongoose/3.5.1" }, // The HTTP storage namespace. // WARNING: the default value (null) will not work in the case of Swift API @@ -313,7 +313,7 @@ } }, // The Mongoose version - "version" : "3.5.0", + "version" : "3.5.1", // The aliasing section mapping the old configuration parameters/values to the current ones "aliasing" : [ diff --git a/docker/Dockerfile b/docker/Dockerfile index 6cff513449..612090ef90 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -6,4 +6,4 @@ RUN ln -s /opt/mongoose-* /opt/mongoose EXPOSE 9010 -ENTRYPOINT ["java", "-Dcom.sun.management.jmxremote", "-Dcom.sun.management.jmxremote.port=9010", "-Dcom.sun.management.jmxremote.rmi.port=9010", "-Dcom.sun.management.jmxremote.local.only=false", "-Dcom.sun.management.jmxremote.authenticate=false", "-Dcom.sun.management.jmxremote.ssl=false", "-jar", "/opt/mongoose/mongoose.jar"] +ENTRYPOINT ["java", "-jar", "/opt/mongoose/mongoose.jar"] diff --git a/load/controller/src/main/java/com/emc/mongoose/load/controller/BasicLoadController.java b/load/controller/src/main/java/com/emc/mongoose/load/controller/BasicLoadController.java index 09aab72ed8..10912bce18 100644 --- a/load/controller/src/main/java/com/emc/mongoose/load/controller/BasicLoadController.java +++ b/load/controller/src/main/java/com/emc/mongoose/load/controller/BasicLoadController.java @@ -674,8 +674,7 @@ protected void doShutdown() Loggers.ERR.warn("{}: load controller shutdown timeout", getName()); } } catch(final InterruptedException e) { - LogUtil.exception(Level.WARN, e, "{}: load controller shutdown interrupted", getName()); - throw new CancellationException(); + throw new CancellationException(e.getMessage()); } } @@ -779,9 +778,7 @@ protected final void doInterrupt() Loggers.ERR.warn("{}: storage drivers interrupting timeout", getName()); } } catch(final InterruptedException e) { - LogUtil.exception( - Level.WARN, e, "{}: storage drivers interrupting interrupted", getName() - ); + throw new CancellationException(e.getMessage()); } for(final Coroutine transferCoroutine : transferCoroutines) { @@ -792,7 +789,8 @@ protected final void doInterrupt() } final ExecutorService ioResultsExecutor = Executors.newFixedThreadPool( - ThreadUtil.getHardwareThreadCount(), new LogContextThreadFactory("ioResultsWorker", true) + ThreadUtil.getHardwareThreadCount(), + new LogContextThreadFactory("ioResultsWorker", true) ); synchronized(driversMap) { for(final LoadGenerator generator : generatorsMap.values()) { @@ -843,10 +841,7 @@ protected final void doInterrupt() ); } } catch(final InterruptedException e) { - LogUtil.exception( - Level.WARN, e, - "{}: interrupted while getting and processing the final I/O results", getName() - ); + throw new CancellationException(e.getMessage()); } } @@ -874,7 +869,8 @@ protected final void doInterrupt() ); } } - } catch(final InterruptedException ignored) { + } catch(final InterruptedException e) { + throw new CancellationException(e.getMessage()); } finally { Loggers.MSG.info("{}: I/O results output done", name); } @@ -900,7 +896,7 @@ protected final void doInterrupt() try { MetricsManager.unregister(this, nextStats); } catch(final InterruptedException e) { - LogUtil.exception(Level.WARN, e, "{}: metrics context unregister failure", name); + throw new CancellationException(e.getMessage()); } } @@ -911,39 +907,68 @@ protected final void doInterrupt() protected final void doClose() throws IOException { + final ExecutorService closeExecutor = Executors.newFixedThreadPool( + ThreadUtil.getHardwareThreadCount(), + new LogContextThreadFactory("interruptWorker", true) + ); + synchronized (driversMap) { for(final LoadGenerator generator : driversMap.keySet()) { - try { - generator.close(); - Loggers.MSG.debug( - "{}: the load generator \"{}\" has been closed", getName(), generator - ); - } catch(final IOException e) { - LogUtil.exception( - Level.WARN, e, "{}: failed to close the generator {}", getName(), generator + closeExecutor.submit( + () -> { + try { + generator.close(); + Loggers.MSG.debug( + "{}: the load generator \"{}\" has been closed", getName(), + generator + ); + } catch(final IOException e) { + LogUtil.exception( + Level.WARN, e, "{}: failed to close the generator {}", getName(), + generator + ); + } + } + ); + + for(final StorageDriver driver : driversMap.get(generator)) { + closeExecutor.submit( + () -> { + try { + driver.close(); + Loggers.MSG.debug("{}: next storage driver {} closed", getName(), + ((driver instanceof Service) ? + ((Service) driver).getName() + " @ " + + ServiceUtil.getAddress((Service) driver) : + driver.toString()) + ); + } catch(final NoSuchObjectException ignored) { + // closing causes this normally + } catch(final IOException e) { + LogUtil.exception( + Level.WARN, e, "{}: failed to close the driver {}", + getName(), driver.toString() + ); + } + } ); } + } - for(final StorageDriver driver : driversMap.get(generator)) { - try { - driver.close(); - Loggers.MSG.debug("{}: next storage driver {} closed", getName(), - ((driver instanceof Service) ? - ((Service) driver).getName() + " @ " + - ServiceUtil.getAddress((Service) driver) : - driver.toString()) - ); - } catch(final NoSuchObjectException ignored) { - // closing causes this normally - } catch(final IOException e) { - LogUtil.exception( - Level.WARN, e, "{}: failed to close the driver {}", - getName(), driver.toString() - ); - } + closeExecutor.shutdown(); + try { + if(closeExecutor.awaitTermination(10, TimeUnit.SECONDS)) { + Loggers.MSG.debug( + "{}: all generators and storage drivers have been closed in time", getName() + ); + } else { + closeExecutor.shutdownNow(); + Loggers.ERR.warn("{}: timeout while closing storage driver(s)", getName()); } + } catch(final InterruptedException e) { + throw new CancellationException(e.getMessage()); } generatorsMap.clear(); diff --git a/tests/unit/src/test/java/com/emc/mongoose/tests/unit/ConfigTest.java b/tests/unit/src/test/java/com/emc/mongoose/tests/unit/ConfigTest.java index afde51b048..a03d40b6cc 100644 --- a/tests/unit/src/test/java/com/emc/mongoose/tests/unit/ConfigTest.java +++ b/tests/unit/src/test/java/com/emc/mongoose/tests/unit/ConfigTest.java @@ -46,7 +46,7 @@ public void shouldParseWithoutFireballsThrowing() throws IOException { final Config config = Config.loadDefaults(); assertThat(config, notNullValue()); - assertThat(config.getVersion(), equalTo("3.5.0", "version")); + assertThat(config.getVersion(), equalTo("3.5.1", "version")); final NetConfig netConfig = config.getStorageConfig().getNetConfig(); assertThat(netConfig, notNullValue()); assertThat(netConfig.getTimeoutMilliSec(), equalTo(0, "storage.net.timeoutMilliSec")); @@ -149,7 +149,7 @@ public void shouldParseWithoutFireballsThrowing() assertThat(headers.containsKey(HttpConfig.KEY_HEADER_USER_AGENT), equalTo(true, "storage.net.http.headers[User-Agent]")); assertThat(headers.get(HttpConfig.KEY_HEADER_USER_AGENT), - equalTo("mongoose/3.5.0", "storage.net.http.headers[User-Agent]")); + equalTo("mongoose/3.5.1", "storage.net.http.headers[User-Agent]")); assertThat(httpConfig.getNamespace(), nullValue("storage.net.http.namespace")); assertThat(httpConfig.getVersioning(), equalTo(false, "storage.net.http.versioning")); assertThat(