From d6824d31a815c0e2068f883b23d2800bc909fb39 Mon Sep 17 00:00:00 2001 From: fickludd Date: Wed, 21 Jun 2017 10:36:14 +0200 Subject: [PATCH] Read multiple properties from single node --- .../store/prototype/neole/PropertyCursor.java | 85 +++++++++++-------- .../prototype/neole/PropertyCursorTest.java | 54 +++++++++++- 2 files changed, 103 insertions(+), 36 deletions(-) diff --git a/enterprise/runtime/neole/src/main/java/org/neo4j/impl/store/prototype/neole/PropertyCursor.java b/enterprise/runtime/neole/src/main/java/org/neo4j/impl/store/prototype/neole/PropertyCursor.java index 34da34c683697..db9e94b1e2d14 100644 --- a/enterprise/runtime/neole/src/main/java/org/neo4j/impl/store/prototype/neole/PropertyCursor.java +++ b/enterprise/runtime/neole/src/main/java/org/neo4j/impl/store/prototype/neole/PropertyCursor.java @@ -24,13 +24,15 @@ import org.neo4j.values.ValueWriter; import org.neo4j.values.Values; +import static org.neo4j.impl.store.prototype.neole.ReadStore.combineReference; + class PropertyCursor extends org.neo4j.impl.store.prototype.PropertyCursor { /** *
      *  0: high bits  ( 1 byte)
-     *  1: next       ( 4 bytes)
-     *  5: prev       ( 4 bytes)
+     *  1: next       ( 4 bytes)    where new property records are added
+     *  5: prev       ( 4 bytes)    points to more PropertyRecords in this chain
      *  9: payload    (32 bytes - 4 x 8 byte blocks)
      * 
*

high bits

@@ -95,6 +97,12 @@ class PropertyCursor extends org.neo4j.impl.store.prototype.PropertyCursor> 24; - if ( typeId == DOUBLE || - (typeId == LONG && ( valueBytes & 0x0000_0000_1000_0000 ) == 0 ) ) + long next = prevPropertyRecordReference(); + block = -1; + if ( next == NO_PROPERTIES ) { - if ( moreBlocksInRecord() ) - { - return 2; - } - else - { - throw new UnsupportedOperationException( "not implemented" ); // long bytes in next record - } + close(); + return false; } - return 1; + return gotoVirtualAddress( next ); } @Override @@ -213,7 +203,7 @@ public Value propertyValue() { if ( moreBlocksInRecord() ) { - return block( this.block + 1 ); + return Values.longValue( block( this.block + 1 ) ); } else { @@ -225,7 +215,7 @@ public Value propertyValue() return Values.floatValue( Float.intBitsToFloat((int)((block( this.block ) & 0x0FFF_FFFF_F000_0000L) >> 28) ) ); case DOUBLE: - return Double.longBitsToDouble( block( this.block + 1 ) ); + return Values.doubleValue( Double.longBitsToDouble( block( this.block + 1 ) ) ); case STRING_REFERENCE: throw new UnsupportedOperationException( "not implemented" ); case ARRAY_REFERENCE: @@ -239,6 +229,12 @@ public Value propertyValue() } } + @Override + protected int dataBound() + { + return RECORD_SIZE; + } + private boolean moreBlocksInRecord() { return block < 3; @@ -250,15 +246,36 @@ public void writeTo( ValueWriter target ) throw new UnsupportedOperationException( "not implemented" ); } - @Override - protected int dataBound() + private int blocksUsedByCurrent() { - return RECORD_SIZE; + if ( block == -1 ) + { + return 1; + } + long valueBytes = block( this.block ); + long typeId = (valueBytes & 0x1F00_0000L) >> 24; + if ( typeId == DOUBLE || + (typeId == LONG && ( valueBytes & 0x0000_0000_1000_0000 ) == 0 ) ) + { + if ( moreBlocksInRecord() ) + { + return 2; + } + else + { + throw new UnsupportedOperationException( "not implemented" ); // long/double bytes in next record + } + } + return 1; } - void init( StoreFile properties, long reference ) + private long nextPropertyRecordReference() { - ReadStore.setup( properties, this, reference ); - block = -1; + return combineReference( unsignedInt( 1 ), ((long) unsignedByte( 0 ) & 0x0FL) << 32 ); + } + + private long prevPropertyRecordReference() + { + return combineReference( unsignedInt( 5 ), ((long) unsignedByte( 0 ) & 0xF0L) << 31 ); } } diff --git a/enterprise/runtime/neole/src/test/java/org/neo4j/impl/store/prototype/neole/PropertyCursorTest.java b/enterprise/runtime/neole/src/test/java/org/neo4j/impl/store/prototype/neole/PropertyCursorTest.java index 7e02118830dea..58be4a50407dc 100644 --- a/enterprise/runtime/neole/src/test/java/org/neo4j/impl/store/prototype/neole/PropertyCursorTest.java +++ b/enterprise/runtime/neole/src/test/java/org/neo4j/impl/store/prototype/neole/PropertyCursorTest.java @@ -22,6 +22,9 @@ import org.junit.ClassRule; import org.junit.Test; +import java.util.HashSet; +import java.util.Set; + import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Transaction; @@ -36,7 +39,7 @@ public class PropertyCursorTest { private static long bare, byteProp, shortProp, intProp, inlineLongProp, longProp, - floatProp, doubleProp, trueProp, falseProp; + floatProp, doubleProp, trueProp, falseProp, allProps; @ClassRule public static final GraphSetup graph = new GraphSetup() @@ -60,6 +63,22 @@ protected void create( GraphDatabaseService graphDb ) trueProp = createNodeWithProperty( graphDb, "trueProp", true ); falseProp = createNodeWithProperty( graphDb, "falseProp", false ); + Node all = graphDb.createNode(); + // first property record + all.setProperty( "byteProp", (byte)13 ); + all.setProperty( "shortProp", (short)13 ); + all.setProperty( "intProp", 13 ); + all.setProperty( "inlineLongProp", 13L ); + // second property record + all.setProperty( "longProp", Long.MAX_VALUE ); + all.setProperty( "floatProp", 13.0f ); + all.setProperty( "doubleProp", 13.0 ); + // ^^^ + // third property record halfway through double? + all.setProperty( "trueProp", true ); + all.setProperty( "falseProp", false ); + allProps = all.getId(); + tx.success(); } } @@ -96,7 +115,7 @@ public void shouldNotAccessNonExistentProperties() throws Exception } @Test - public void shouldAccessIntProperty() throws Exception + public void shouldAccessSingleProperty() throws Exception { assertAccessSingleProperty( byteProp, (byte)13 ); assertAccessSingleProperty( shortProp, (short)13 ); @@ -109,6 +128,37 @@ public void shouldAccessIntProperty() throws Exception assertAccessSingleProperty( falseProp, false ); } + @Test + public void shouldAccessAllNodeProperties() throws Exception + { + // given + try ( NodeCursor node = graph.allocateNodeCursor(); + PropertyCursor props = graph.allocatePropertyCursor() ) + { + // when + graph.singleNode( allProps, node ); + assertTrue( "node by reference", node.next() ); + assertTrue( "has properties", node.hasProperties() ); + + node.properties( props ); + Set values = new HashSet<>(); + while ( props.next() ) + { + values.add( props.propertyValue() ); + } + + assertTrue( "byteProp", values.contains( (byte)13 ) ); + assertTrue( "shortProp", values.contains( (short)13 ) ); + assertTrue( "intProp", values.contains( 13 ) ); + assertTrue( "inlineLongProp", values.contains( 13L ) ); + assertTrue( "longProp", values.contains( Long.MAX_VALUE ) ); + assertTrue( "floatProp", values.contains( 13.0f ) ); + assertTrue( "doubleProp", values.contains( 13.0 ) ); + assertTrue( "trueProp", values.contains( true ) ); + assertTrue( "falseProp", values.contains( false ) ); + } + } + private void assertAccessSingleProperty( long nodeId, Object expectedValue ) { // given