diff --git a/driver/src/main/java/org/neo4j/driver/internal/summary/InternalProfiledPlan.java b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalProfiledPlan.java index 910c586483..8641b7ee35 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/summary/InternalProfiledPlan.java +++ b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalProfiledPlan.java @@ -20,22 +20,30 @@ import java.util.List; import java.util.Map; +import java.util.function.Function; import org.neo4j.driver.Value; import org.neo4j.driver.summary.ProfiledPlan; -import java.util.function.Function; public class InternalProfiledPlan extends InternalPlan implements ProfiledPlan { private final long dbHits; private final long records; + private final long pageCacheHits; + private final long pageCacheMisses; + private final double pageCacheHitRatio; + private final long time; - protected InternalProfiledPlan( String operatorType, Map arguments, - List identifiers, List children, long dbHits, long records ) + protected InternalProfiledPlan( String operatorType, Map arguments, List identifiers, List children, long dbHits, + long records, long pageCacheHits, long pageCacheMisses, double pageCacheHitRatio, long time ) { super( operatorType, arguments, identifiers, children ); this.dbHits = dbHits; this.records = records; + this.pageCacheHits = pageCacheHits; + this.pageCacheMisses = pageCacheMisses; + this.pageCacheHitRatio = pageCacheHitRatio; + this.time = time; } @Override @@ -50,17 +58,51 @@ public long records() return records; } + @Override + public boolean hasPageCacheStats() + { + return pageCacheHits > 0 || pageCacheMisses > 0 || !Double.isNaN( pageCacheHitRatio ); + } + + @Override + public long pageCacheHits() + { + return pageCacheHits; + } + + @Override + public long pageCacheMisses() + { + return pageCacheMisses; + } + + @Override + public double pageCacheHitRatio() + { + return pageCacheHitRatio; + } + + @Override + public long time() + { + return time; + } + public static final PlanCreator PROFILED_PLAN = new PlanCreator() { @Override - public ProfiledPlan create( String operatorType, Map arguments, List identifiers, List children, Value originalPlanValue ) + public ProfiledPlan create( String operatorType, Map arguments, List identifiers, List children, + Value originalPlanValue ) { - return new InternalProfiledPlan( operatorType, arguments, identifiers, children, - originalPlanValue.get( "dbHits" ).asLong(), - originalPlanValue.get( "rows" ).asLong() ); + return new InternalProfiledPlan( operatorType, arguments, identifiers, children, originalPlanValue.get( "dbHits" ).asLong( 0 ), + originalPlanValue.get( "rows" ).asLong( 0 ), originalPlanValue.get( "pageCacheHits" ).asLong( 0 ), + originalPlanValue.get( "pageCacheMisses" ).asLong( 0 ), originalPlanValue.get( "pageCacheHitRatio" ).asDouble( Double.NaN ), + originalPlanValue.get( "time" ).asLong( 0 ) ); } }; - /** Builds a regular plan without profiling information - eg. a plan that came as a result of an `EXPLAIN` statement */ - public static final Function PROFILED_PLAN_FROM_VALUE = new Converter<>(PROFILED_PLAN); + /** + * Builds a regular plan without profiling information - eg. a plan that came as a result of an `EXPLAIN` statement + */ + public static final Function PROFILED_PLAN_FROM_VALUE = new Converter<>( PROFILED_PLAN ); } diff --git a/driver/src/main/java/org/neo4j/driver/summary/ProfiledPlan.java b/driver/src/main/java/org/neo4j/driver/summary/ProfiledPlan.java index d354c71567..b00de965a6 100644 --- a/driver/src/main/java/org/neo4j/driver/summary/ProfiledPlan.java +++ b/driver/src/main/java/org/neo4j/driver/summary/ProfiledPlan.java @@ -37,6 +37,31 @@ public interface ProfiledPlan extends Plan */ long records(); + /** + * @return if the number page cache hits and misses and the ratio was recorded. + */ + boolean hasPageCacheStats(); + + /** + * @return number of page cache hits caused by executing the associated execution step + */ + long pageCacheHits(); + + /** + * @return number of page cache misses caused by executing the associated execution step + */ + long pageCacheMisses(); + + /** + * @return the ratio of page cache hits to total number of lookups or {@link Double#NaN} if no data is available + */ + double pageCacheHitRatio(); + + /** + * @return amount of time spent in the associated execution step. + */ + long time(); + @Override List children(); } diff --git a/driver/src/test/java/org/neo4j/driver/integration/SummaryIT.java b/driver/src/test/java/org/neo4j/driver/integration/SummaryIT.java index bd62e60beb..46e03d8154 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/SummaryIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/SummaryIT.java @@ -185,6 +185,7 @@ void shouldContainProfile() ProfiledPlan profile = summary.profile(); + assertEquals( 0, profile.time() ); assertEquals( 0, profile.dbHits() ); assertEquals( 1, profile.records() ); } diff --git a/driver/src/test/java/org/neo4j/driver/internal/summary/InternalProfiledPlanTest.java b/driver/src/test/java/org/neo4j/driver/internal/summary/InternalProfiledPlanTest.java index 1ea0045e78..0e83a3d064 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/summary/InternalProfiledPlanTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/summary/InternalProfiledPlanTest.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.Map; +import org.neo4j.driver.internal.value.FloatValue; import org.neo4j.driver.internal.value.IntegerValue; import org.neo4j.driver.internal.value.ListValue; import org.neo4j.driver.internal.value.MapValue; @@ -35,6 +36,7 @@ import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; +import static org.junit.jupiter.api.Assertions.assertTrue; class InternalProfiledPlanTest { @@ -49,12 +51,7 @@ void shouldHandlePlanWithNoChildren() ProfiledPlan plan = InternalProfiledPlan.PROFILED_PLAN_FROM_VALUE.apply( value ); // THEN - assertThat( plan.dbHits(), equalTo( 42L ) ); - assertThat( plan.records(), equalTo( 1337L ) ); - assertThat( plan.operatorType(), equalTo( "AwesomeOperator" ) ); - assertThat( plan.identifiers(), equalTo( asList( "n1", "n2" ) ) ); - assertThat( plan.arguments().values(), hasItem( new StringValue( "CYPHER 1337" ) ) ); - assertThat( plan.children(), empty() ); + verifyPlan( plan ); } @Test @@ -71,12 +68,7 @@ void shouldHandlePlanWithChildren() // THEN for ( ProfiledPlan child : plan.children() ) { - assertThat( child.dbHits(), equalTo( 42L ) ); - assertThat( child.records(), equalTo( 1337L ) ); - assertThat( child.operatorType(), equalTo( "AwesomeOperator" ) ); - assertThat( child.identifiers(), equalTo( asList( "n1", "n2" ) ) ); - assertThat( child.arguments().values(), hasItem( new StringValue( "CYPHER 1337" ) ) ); - assertThat( child.children(), empty() ); + verifyPlan( child ); } } @@ -86,6 +78,10 @@ private Map createPlanMap() map.put( "operatorType", new StringValue( "AwesomeOperator" ) ); map.put( "rows", new IntegerValue( 1337L ) ); map.put( "dbHits", new IntegerValue( 42 ) ); + map.put( "pageCacheHits", new IntegerValue( 1234 ) ); + map.put( "pageCacheMisses", new IntegerValue( 3456 ) ); + map.put( "pageCacheHitRatio", new FloatValue( 0.123 ) ); + map.put( "time", new IntegerValue( 999 ) ); map.put( "identifiers", new ListValue( new StringValue( "n1" ), new StringValue( "n2" ) ) ); Map args = new HashMap<>(); args.put( "version", new StringValue( "CYPHER 1337" ) ); @@ -93,5 +89,18 @@ private Map createPlanMap() return map; } - + private void verifyPlan( ProfiledPlan plan ) + { + assertThat( plan.dbHits(), equalTo( 42L ) ); + assertThat( plan.records(), equalTo( 1337L ) ); + assertTrue( plan.hasPageCacheStats() ); + assertThat( plan.pageCacheHits(), equalTo( 1234L ) ); + assertThat( plan.pageCacheMisses(), equalTo( 3456L ) ); + assertThat( plan.pageCacheHitRatio(), equalTo( 0.123 ) ); + assertThat( plan.time(), equalTo( 999L ) ); + assertThat( plan.operatorType(), equalTo( "AwesomeOperator" ) ); + assertThat( plan.identifiers(), equalTo( asList( "n1", "n2" ) ) ); + assertThat( plan.arguments().values(), hasItem( new StringValue( "CYPHER 1337" ) ) ); + assertThat( plan.children(), empty() ); + } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/util/MetadataExtractorTest.java b/driver/src/test/java/org/neo4j/driver/internal/util/MetadataExtractorTest.java index 66aa9298b1..511faeeb11 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/util/MetadataExtractorTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/util/MetadataExtractorTest.java @@ -228,6 +228,7 @@ void shouldBuildResultSummaryWithProfiledPlan() "identifiers", values( "a", "b" ), "rows", value( 424242 ), "dbHits", value( 242424 ), + "time", value( 999 ), "children", values( parameters( "operatorType", "LabelScan", @@ -249,6 +250,11 @@ void shouldBuildResultSummaryWithProfiledPlan() assertEquals( asList( "a", "b" ), summary.profile().identifiers() ); assertEquals( 424242, summary.profile().records() ); assertEquals( 242424, summary.profile().dbHits() ); + assertEquals( 999, summary.profile().time() ); + assertFalse( summary.profile().hasPageCacheStats() ); + assertEquals( Double.NaN, summary.profile().pageCacheHitRatio() ); + assertEquals( 0, summary.profile().pageCacheMisses() ); + assertEquals( 0, summary.profile().pageCacheHits() ); List children = summary.profile().children(); assertEquals( 1, children.size() );