diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/ExecutionMonitors.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/ExecutionMonitors.java index 470f948f3bd32..41edc0bc21027 100644 --- a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/ExecutionMonitors.java +++ b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/ExecutionMonitors.java @@ -31,9 +31,10 @@ private ExecutionMonitors() public static ExecutionMonitor defaultVisible() { + ProgressRestoringMonitor monitor = new ProgressRestoringMonitor(); return new MultiExecutionMonitor( - new HumanUnderstandableExecutionMonitor( System.out ), - new OnDemandDetailsExecutionMonitor( System.out ) ); + new HumanUnderstandableExecutionMonitor( System.out, monitor ), + new OnDemandDetailsExecutionMonitor( System.out, monitor ) ); } private static final ExecutionMonitor INVISIBLE = new ExecutionMonitor() diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/HumanUnderstandableExecutionMonitor.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/HumanUnderstandableExecutionMonitor.java index 231b5c6d351e9..658c10bf4eb96 100644 --- a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/HumanUnderstandableExecutionMonitor.java +++ b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/HumanUnderstandableExecutionMonitor.java @@ -58,6 +58,11 @@ */ public class HumanUnderstandableExecutionMonitor implements ExecutionMonitor { + public interface Monitor + { + boolean somethingElseBrokeMyNiceOutput(); + } + private static final String ESTIMATED_REQUIRED_MEMORY_USAGE = "Estimated required memory usage"; private static final String ESTIMATED_DISK_SPACE_USAGE = "Estimated disk space usage"; private static final String ESTIMATED_NUMBER_OF_RELATIONSHIP_PROPERTIES = "Estimated number of relationship properties"; @@ -70,6 +75,7 @@ public class HumanUnderstandableExecutionMonitor implements ExecutionMonitor // assigned later on private final PrintStream out; + private final Monitor monitor; private DependencyResolver dependencyResolver; // progress of current stage @@ -77,9 +83,10 @@ public class HumanUnderstandableExecutionMonitor implements ExecutionMonitor private long stashedProgress; private long progress; - public HumanUnderstandableExecutionMonitor( PrintStream out ) + public HumanUnderstandableExecutionMonitor( PrintStream out, Monitor monitor ) { this.out = out; + this.monitor = monitor; } @Override @@ -385,12 +392,27 @@ public long nextCheckTime() @Override public void check( StageExecution execution ) { + reprintProgressIfNecessary(); if ( includeStage( execution ) ) { updateProgress( progressOf( execution ) ); } } + private void reprintProgressIfNecessary() + { + if ( monitor.somethingElseBrokeMyNiceOutput() ) + { + long prevProgress = this.progress; + long prevStashedProgress = this.stashedProgress; + this.progress = 0; + this.stashedProgress = 0; + updateProgress( prevProgress + prevStashedProgress ); + this.progress = prevProgress; + this.stashedProgress = prevStashedProgress; + } + } + private static boolean includeStage( StageExecution execution ) { String name = execution.getStageName(); diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/OnDemandDetailsExecutionMonitor.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/OnDemandDetailsExecutionMonitor.java index 16b2a783ab1a2..78e08b375bbaa 100644 --- a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/OnDemandDetailsExecutionMonitor.java +++ b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/OnDemandDetailsExecutionMonitor.java @@ -41,7 +41,6 @@ import org.neo4j.unsafe.impl.batchimport.stats.StepStats; import static java.lang.Long.max; -import static java.lang.String.format; import static java.lang.System.currentTimeMillis; import static org.neo4j.helpers.Format.bytes; @@ -65,18 +64,33 @@ */ public class OnDemandDetailsExecutionMonitor implements ExecutionMonitor { + public interface Monitor + { + public void detailsPrinted(); + } + + public static final Monitor NO_MONITOR = new Monitor() + { + @Override + public void detailsPrinted() + { // ignored + } + }; + private final List details = new ArrayList<>(); private final PrintStream out; private final Map> actions = new HashMap<>(); private final CollectingMonitor gcBlockTime = new CollectingMonitor(); private final MeasureDoNothing gcMonitor; + private final Monitor monitor; private StageDetails current; private boolean printDetailsOnDone; - public OnDemandDetailsExecutionMonitor( PrintStream out ) + public OnDemandDetailsExecutionMonitor( PrintStream out, Monitor monitor ) { this.out = out; + this.monitor = monitor; this.actions.put( "i", Pair.of( "Print more detailed information", this::printDetails ) ); this.actions.put( "c", Pair.of( "Print more detailed information about current stage", this::printDetailsForCurrentStage ) ); this.actions.put( "gc", Pair.of( "Trigger GC", this::triggerGC ) ); @@ -135,11 +149,24 @@ private void printDetails() stageDetails.print( out ); } - out.println( "Environment information:"); - out.println( " Free physical memory: " + bytes( OsBeanUtil.getFreePhysicalMemory() ) ); - out.println( " Max VM memory: " + bytes( Runtime.getRuntime().maxMemory() ) ); - out.println( " Free VM memory: " + bytes( Runtime.getRuntime().freeMemory() ) ); - out.println( " GC block time: " + duration( gcBlockTime.getGcBlockTime() ) ); + printIndented( out, "Environment information:" ); + printIndented( out, " Free physical memory: " + bytes( OsBeanUtil.getFreePhysicalMemory() ) ); + printIndented( out, " Max VM memory: " + bytes( Runtime.getRuntime().maxMemory() ) ); + printIndented( out, " Free VM memory: " + bytes( Runtime.getRuntime().freeMemory() ) ); + printIndented( out, " GC block time: " + duration( gcBlockTime.getGcBlockTime() ) ); + out.println(); + } + + private void printDetailsHeadline() + { + out.println(); + out.println(); + printIndented( out, "************** DETAILS **************" ); + out.println(); + + // Make sure that if user is interested in details then also print the entire details set when import is done + printDetailsOnDone = true; + monitor.detailsPrinted(); } private void printDetailsForCurrentStage() @@ -151,12 +178,9 @@ private void printDetailsForCurrentStage() } } - private void printDetailsHeadline() + private static void printIndented( PrintStream out, String string ) { - out.println( format( "%n************** DETAILS **************%n" ) ); - - // Make sure that if user is interested in details then also print the entire details set when import is done - printDetailsOnDone = true; + out.println( "\t" + string ); } private void triggerGC() @@ -209,10 +233,10 @@ private static class StageDetails void print( PrintStream out ) { - out.println( execution.name() ); + printIndented( out, execution.name() ); StringBuilder builder = new StringBuilder(); SpectrumExecutionMonitor.printSpectrum( builder, execution, SpectrumExecutionMonitor.DEFAULT_WIDTH, DetailLevel.NO ); - out.println( builder.toString() ); + printIndented( out, builder.toString() ); printValue( out, memoryUsage, "Memory usage", Format::bytes ); printValue( out, ioThroughput, "I/O throughput", value -> bytes( value ) + "/s" ); printValue( out, stageGcBlockTime, "GC block time", Format::duration ); @@ -226,7 +250,7 @@ private static void printValue( PrintStream out, long value, String description, { if ( value > 0 ) { - out.println( description + ": " + toStringConverter.apply( value ) ); + printIndented( out, description + ": " + toStringConverter.apply( value ) ); } } diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/ProgressRestoringMonitor.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/ProgressRestoringMonitor.java new file mode 100644 index 0000000000000..4238bd1580a66 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/staging/ProgressRestoringMonitor.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002-2017 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.unsafe.impl.batchimport.staging; + +import org.neo4j.unsafe.impl.batchimport.staging.HumanUnderstandableExecutionMonitor.Monitor; + +public class ProgressRestoringMonitor implements Monitor, org.neo4j.unsafe.impl.batchimport.staging.OnDemandDetailsExecutionMonitor.Monitor +{ + private volatile boolean detailsPrinted; + + @Override + public void detailsPrinted() + { + this.detailsPrinted = true; + } + + @Override + public boolean somethingElseBrokeMyNiceOutput() + { + if ( detailsPrinted ) + { + detailsPrinted = false; + return true; + } + return false; + } +}