diff --git a/community/kernel/src/main/java/org/neo4j/kernel/InternalAbstractGraphDatabase.java b/community/kernel/src/main/java/org/neo4j/kernel/InternalAbstractGraphDatabase.java
index 16a0830058360..853e66f8e3d48 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/InternalAbstractGraphDatabase.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/InternalAbstractGraphDatabase.java
@@ -110,7 +110,6 @@
import org.neo4j.kernel.impl.core.NodeProxy.NodeActions;
import org.neo4j.kernel.impl.core.PropertyKeyTokenHolder;
import org.neo4j.kernel.impl.core.ReadOnlyTokenCreator;
-import org.neo4j.kernel.impl.core.RelationshipData;
import org.neo4j.kernel.impl.core.RelationshipProxy.RelationshipActions;
import org.neo4j.kernel.impl.core.RelationshipTypeTokenHolder;
import org.neo4j.kernel.impl.core.StartupStatistics;
@@ -131,6 +130,8 @@
import org.neo4j.kernel.impl.locking.ResourceTypes;
import org.neo4j.kernel.impl.locking.community.CommunityLockManger;
import org.neo4j.kernel.impl.pagecache.LifecycledPageCache;
+import org.neo4j.kernel.impl.query.QueryEngineProvider;
+import org.neo4j.kernel.impl.query.QueryExecutionEngine;
import org.neo4j.kernel.impl.query.QueryExecutionKernelException;
import org.neo4j.kernel.impl.store.NeoStore;
import org.neo4j.kernel.impl.store.StoreFactory;
@@ -168,11 +169,10 @@
import org.neo4j.kernel.logging.Logging;
import org.neo4j.kernel.logging.RollingLogMonitor;
import org.neo4j.kernel.monitoring.Monitors;
-import org.neo4j.kernel.impl.query.QueryEngineProvider;
-import org.neo4j.kernel.impl.query.QueryExecutionEngine;
import org.neo4j.tooling.GlobalGraphOperations;
import static java.lang.String.format;
+
import static org.neo4j.collection.primitive.PrimitiveLongCollections.map;
import static org.neo4j.helpers.Settings.STRING;
import static org.neo4j.helpers.Settings.setting;
@@ -773,21 +773,6 @@ public Node newNodeProxy( long nodeId )
return nodeManager.newNodeProxyById( nodeId );
}
- @Override
- public RelationshipData getRelationshipData( long relationshipId )
- {
- try ( Statement statement = threadToTransactionBridge.instance() )
- {
- RelationshipData data = new RelationshipData();
- statement.readOperations().relationshipVisit( relationshipId, data );
- return data;
- }
- catch ( EntityNotFoundException e )
- {
- throw new NotFoundException( e );
- }
- }
-
@Override
public RelationshipType getRelationshipTypeById( int type )
{
@@ -833,10 +818,22 @@ public void failTransaction()
}
@Override
- public Relationship newRelationshipProxy( long id )
+ public Relationship lazyRelationshipProxy( long id )
{
return nodeManager.newRelationshipProxyById( id );
}
+
+ @Override
+ public Relationship newRelationshipProxy( long id )
+ {
+ return nodeManager.newRelationshipProxy( id );
+ }
+
+ @Override
+ public Relationship newRelationshipProxy( long id, long startNodeId, int typeId, long endNodeId )
+ {
+ return nodeManager.newRelationshipProxy( id, startNodeId, typeId, endNodeId );
+ }
};
}
@@ -1101,7 +1098,7 @@ public Relationship getRelationshipById( long id )
throw new NotFoundException( format( "Relationship %d not found", id ) );
}
- return nodeManager.newRelationshipProxyById( id );
+ return nodeManager.newRelationshipProxy( id );
}
}
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeManager.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeManager.java
index 4830285b90a2c..6140ee6b995a1 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeManager.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeManager.java
@@ -23,8 +23,11 @@
import java.util.concurrent.CopyOnWriteArrayList;
import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.NotFoundException;
import org.neo4j.graphdb.Relationship;
import org.neo4j.kernel.PropertyTracker;
+import org.neo4j.kernel.api.Statement;
+import org.neo4j.kernel.api.exceptions.EntityNotFoundException;
import org.neo4j.kernel.lifecycle.LifecycleAdapter;
import static java.lang.System.currentTimeMillis;
@@ -69,12 +72,34 @@ public NodeProxy newNodeProxyById( long id )
return new NodeProxy( nodeActions, id );
}
+ /** Returns a "lazy" proxy, where additional fields are initialized on access. */
@Override
public RelationshipProxy newRelationshipProxyById( long id )
{
return new RelationshipProxy( relationshipActions, id );
}
+ /** Returns a fully initialized proxy. */
+ public RelationshipProxy newRelationshipProxy( long id )
+ {
+ try ( Statement statement = threadToTransactionBridge.instance() )
+ {
+ RelationshipProxy proxy = new RelationshipProxy( relationshipActions, id );
+ statement.readOperations().relationshipVisit( id, proxy );
+ return proxy;
+ }
+ catch ( EntityNotFoundException e )
+ {
+ throw new NotFoundException( e );
+ }
+ }
+
+ /** Returns a fully initialized proxy. */
+ public RelationshipProxy newRelationshipProxy( long id, long startNodeId, int typeId, long endNodeId )
+ {
+ return new RelationshipProxy( relationshipActions, id, startNodeId, typeId, endNodeId );
+ }
+
@Override
public GraphPropertiesImpl newGraphProperties()
{
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java
index a7605b55ec47e..0bbf21f112d35 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java
@@ -83,7 +83,11 @@ public interface NodeActions
void failTransaction();
+ Relationship lazyRelationshipProxy( long id );
+
Relationship newRelationshipProxy( long id );
+
+ Relationship newRelationshipProxy( long id, long startNodeId, int typeId, long endNodeId );
}
private final NodeActions actions;
@@ -431,16 +435,16 @@ public Relationship createRelationshipTo( Node otherNode, RelationshipType type
throw new IllegalArgumentException( "Other node is null." );
}
// TODO: This is the checks we would like to do, but we have tests that expect to mix nodes...
- //if ( !(otherNode instanceof NodeProxy) || (((NodeProxy) otherNode).nodeLookup != nodeLookup) )
+ //if ( !(otherNode instanceof NodeProxy) || (((NodeProxy) otherNode).actions != actions) )
//{
// throw new IllegalArgumentException( "Nodes do not belong to same graph database." );
//}
try ( Statement statement = actions.statement() )
{
int relationshipTypeId = statement.tokenWriteOperations().relationshipTypeGetOrCreateForName( type.name() );
- return actions.newRelationshipProxy(
- statement.dataWriteOperations()
- .relationshipCreate( relationshipTypeId, nodeId, otherNode.getId() ) );
+ long relationshipId = statement.dataWriteOperations()
+ .relationshipCreate( relationshipTypeId, nodeId, otherNode.getId() );
+ return actions.newRelationshipProxy( relationshipId, nodeId, relationshipTypeId, otherNode.getId() );
}
catch ( IllegalTokenNameException | RelationshipTypeIdNotFoundKernelException e )
{
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipData.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipData.java
deleted file mode 100644
index d117f982e0094..0000000000000
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipData.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Copyright (c) 2002-2015 "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.kernel.impl.core;
-
-import org.neo4j.kernel.impl.api.RelationshipVisitor;
-
-public class RelationshipData implements RelationshipVisitor
-{
- private long startNode;
- private long endNode;
- private int type;
-
- public long getStartNode()
- {
- return startNode;
- }
-
- public long getEndNode()
- {
- return endNode;
- }
-
- public int getType()
- {
- return type;
- }
-
- @Override
- public void visit( long relIdIgnored, int type, long startNode, long endNode )
- {
- this.startNode = startNode;
- this.endNode = endNode;
- this.type = type;
- }
-}
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipProxy.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipProxy.java
index a79c8deeb4877..9fe8956ad02e8 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipProxy.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipProxy.java
@@ -39,9 +39,10 @@
import org.neo4j.kernel.api.exceptions.schema.IllegalTokenNameException;
import org.neo4j.kernel.api.properties.DefinedProperty;
import org.neo4j.kernel.api.properties.Property;
+import org.neo4j.kernel.impl.api.RelationshipVisitor;
import org.neo4j.kernel.impl.api.operations.KeyReadOperations;
-public class RelationshipProxy implements Relationship
+public class RelationshipProxy implements Relationship, RelationshipVisitor
{
public interface RelationshipActions
{
@@ -49,8 +50,6 @@ public interface RelationshipActions
Node newNodeProxy( long nodeId );
- RelationshipData getRelationshipData( long relationshipId );
-
RelationshipType getRelationshipTypeById( int type );
GraphDatabaseService getGraphDatabaseService();
@@ -61,18 +60,76 @@ public interface RelationshipActions
}
private final RelationshipActions actions;
- private final long relId;
+ /** [unused,target][source,id] **/
+ private short hiBits;
+ private short type;
+ private int loId, loSource, loTarget;
- public RelationshipProxy( RelationshipActions actions, long relId )
+ public RelationshipProxy( RelationshipActions actions, long id, long startNode, int type, long endNode )
{
- this.relId = relId;
this.actions = actions;
+ visit( id, type, startNode, endNode );
+ }
+
+ public RelationshipProxy( RelationshipActions actions, long id )
+ {
+ this.actions = actions;
+ assert (0xFFFF_FFF0_0000_0000L & id) == 0;
+ this.hiBits = (short) (0xF000 | (id >> 32));
+ this.loId = (int) id;
+ }
+
+ @Override
+ public void visit( long id, int type, long startNode, long endNode ) throws RuntimeException
+ {
+ assert (0xFFFF_FFF0_0000_0000L & id) == 0 && // 36 bits
+ (0xFFFF_FFF0_0000_0000L & startNode) == 0 && // 36 bits
+ (0xFFFF_FFF0_0000_0000L & endNode) == 0 && // 36 bits
+ (0xFFFF_0000 & type) == 0; // 16 bits
+ this.hiBits = (short) ((id >> 32) | ((startNode >> 28) & 0x00F0) | ((startNode >> 28) & 0x0F00));
+ this.type = (short) type;
+ this.loId = (int) id;
+ this.loSource = (int) startNode;
+ this.loTarget = (int) endNode;
+ }
+
+ private void initializeData()
+ {
+ if ( (hiBits & 0xF000) != 0 )
+ {
+ try ( Statement statement = actions.statement() )
+ {
+ statement.readOperations().relationshipVisit( getId(), this );
+ }
+ catch ( EntityNotFoundException e )
+ {
+ throw new NotFoundException( e );
+ }
+ }
}
@Override
public long getId()
{
- return relId;
+ return hiBits == 0 ? loId : ((hiBits & 0x000FL) << 32 | loId);
+ }
+
+ private int typeId()
+ {
+ initializeData();
+ return type & 0xFFFF;
+ }
+
+ private long sourceId()
+ {
+ initializeData();
+ return hiBits == 0 ? loSource : ((hiBits & 0x00F0L) << 28 | loSource);
+ }
+
+ private long targetId()
+ {
+ initializeData();
+ return hiBits == 0 ? loTarget : ((hiBits & 0x0F00L) << 24 | loTarget);
}
@Override
@@ -95,7 +152,7 @@ public void delete()
catch ( EntityNotFoundException e )
{
throw new IllegalStateException( "Unable to delete relationship[" +
- relId + "] since it is already deleted." );
+ getId() + "] since it is already deleted." );
}
}
@@ -103,24 +160,22 @@ public void delete()
public Node[] getNodes()
{
assertInUnterminatedTransaction();
- RelationshipData data = actions.getRelationshipData( relId );
return new Node[]{
- actions.newNodeProxy( data.getStartNode() ),
- actions.newNodeProxy( data.getEndNode() )};
+ actions.newNodeProxy( sourceId() ),
+ actions.newNodeProxy( targetId() )};
}
@Override
public Node getOtherNode( Node node )
{
assertInUnterminatedTransaction();
- RelationshipData data = actions.getRelationshipData( relId );
- if ( data.getStartNode() == node.getId() )
+ if ( sourceId() == node.getId() )
{
- return actions.newNodeProxy( data.getEndNode() );
+ return actions.newNodeProxy( targetId() );
}
- if ( data.getEndNode() == node.getId() )
+ if ( targetId() == node.getId() )
{
- return actions.newNodeProxy( data.getStartNode() );
+ return actions.newNodeProxy( sourceId() );
}
throw new NotFoundException( "Node[" + node.getId()
+ "] not connected to this relationship[" + getId() + "]" );
@@ -130,22 +185,21 @@ public Node getOtherNode( Node node )
public Node getStartNode()
{
assertInUnterminatedTransaction();
- return actions.newNodeProxy( actions.getRelationshipData( relId ).getStartNode() );
+ return actions.newNodeProxy( sourceId() );
}
@Override
public Node getEndNode()
{
assertInUnterminatedTransaction();
- return actions.newNodeProxy( actions.getRelationshipData( relId ).getEndNode() );
+ return actions.newNodeProxy( targetId() );
}
@Override
public RelationshipType getType()
{
assertInUnterminatedTransaction();
- int type = actions.getRelationshipData( relId ).getType();
- return actions.getRelationshipTypeById( type );
+ return actions.getRelationshipTypeById( typeId() );
}
@Override
@@ -189,7 +243,7 @@ public Object getProperty( String key )
{
throw new NotFoundException( String.format( "No such property, '%s'.", key ) );
}
- return statement.readOperations().relationshipGetProperty( relId, propertyId ).value();
+ return statement.readOperations().relationshipGetProperty( getId(), propertyId ).value();
}
catch ( EntityNotFoundException | PropertyNotFoundException e )
{
@@ -210,7 +264,7 @@ public Object getProperty( String key, Object defaultValue )
try ( Statement statement = actions.statement() )
{
int propertyId = statement.readOperations().propertyKeyGetForName( key );
- return statement.readOperations().relationshipGetProperty( relId, propertyId ).value( defaultValue );
+ return statement.readOperations().relationshipGetProperty( getId(), propertyId ).value( defaultValue );
}
catch ( EntityNotFoundException e )
{
@@ -230,7 +284,7 @@ public boolean hasProperty( String key )
{
int propertyId = statement.readOperations().propertyKeyGetForName( key );
return propertyId != KeyReadOperations.NO_SUCH_PROPERTY_KEY &&
- statement.readOperations().relationshipGetProperty( relId, propertyId ).isDefined();
+ statement.readOperations().relationshipGetProperty( getId(), propertyId ).isDefined();
}
catch ( EntityNotFoundException e )
{
@@ -244,7 +298,7 @@ public void setProperty( String key, Object value )
try ( Statement statement = actions.statement() )
{
int propertyKeyId = statement.tokenWriteOperations().propertyKeyGetOrCreateForName( key );
- statement.dataWriteOperations().relationshipSetProperty( relId, Property.property( propertyKeyId, value ) );
+ statement.dataWriteOperations().relationshipSetProperty( getId(), Property.property( propertyKeyId, value ) );
}
catch ( IllegalArgumentException e )
{
@@ -273,7 +327,7 @@ public Object removeProperty( String key )
try ( Statement statement = actions.statement() )
{
int propertyId = statement.tokenWriteOperations().propertyKeyGetOrCreateForName( key );
- return statement.dataWriteOperations().relationshipRemoveProperty( relId, propertyId ).value( null );
+ return statement.dataWriteOperations().relationshipRemoveProperty( getId(), propertyId ).value( null );
}
catch ( EntityNotFoundException e )
{
@@ -294,8 +348,7 @@ public Object removeProperty( String key )
public boolean isType( RelationshipType type )
{
assertInUnterminatedTransaction();
- int typeId = actions.getRelationshipData( relId ).getType();
- return actions.getRelationshipTypeById( typeId ).name().equals( type.name() );
+ return actions.getRelationshipTypeById( typeId() ).name().equals( type.name() );
}
public int compareTo( Object rel )
@@ -326,7 +379,7 @@ public boolean equals( Object o )
@Override
public int hashCode()
{
- return (int) ((relId >>> 32) ^ relId);
+ return (int) ((getId() >>> 32) ^ getId());
}
@Override
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataSnapshot.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataSnapshot.java
index dfadd291607cb..107b4d46646a6 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataSnapshot.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataSnapshot.java
@@ -246,7 +246,7 @@ private Iterable map2Rels( Iterable added )
@Override
public Relationship apply( Long id )
{
- return nodeActions.newRelationshipProxy( id );
+ return nodeActions.lazyRelationshipProxy( id );
}
}, added);
}
@@ -355,7 +355,7 @@ public RelationshipPropertyEntryView( long relId, String key, Object newValue, O
@Override
public Relationship entity()
{
- return nodeActions.newRelationshipProxy( relId );
+ return nodeActions.lazyRelationshipProxy( relId );
}
@Override
diff --git a/community/kernel/src/main/java/org/neo4j/tooling/GlobalGraphOperations.java b/community/kernel/src/main/java/org/neo4j/tooling/GlobalGraphOperations.java
index 69ed5095e2eee..6d80a92418ae6 100644
--- a/community/kernel/src/main/java/org/neo4j/tooling/GlobalGraphOperations.java
+++ b/community/kernel/src/main/java/org/neo4j/tooling/GlobalGraphOperations.java
@@ -136,7 +136,7 @@ public void close()
@Override
protected Relationship fetchNextOrNull()
{
- return ids.hasNext() ? nodeManager.newRelationshipProxyById( ids.next() ) : null;
+ return ids.hasNext() ? nodeManager.newRelationshipProxy( ids.next() ) : null;
}
};
}
diff --git a/community/kernel/src/test/java/org/neo4j/kernel/TestGuard.java b/community/kernel/src/test/java/org/neo4j/kernel/TestGuard.java
index 4268eb0ffe717..ba71f82c2be56 100644
--- a/community/kernel/src/test/java/org/neo4j/kernel/TestGuard.java
+++ b/community/kernel/src/test/java/org/neo4j/kernel/TestGuard.java
@@ -104,7 +104,7 @@ public void testGuardOnDifferentGraphOps()
ignore( position );
}
Guard.OperationsCount ops4 = getGuard( db ).stop();
- assertEquals( 3, ops4.getOpsCount() );
+ assertEquals( 4, ops4.getOpsCount() );
}
db.shutdown();
diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataViewTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataViewTest.java
index a3f17352edc58..dbdf83853cb34 100644
--- a/community/kernel/src/test/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataViewTest.java
+++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataViewTest.java
@@ -283,7 +283,7 @@ private TxStateTransactionDataSnapshot snapshot()
{
NodeProxy.NodeActions nodeActions = mock( NodeProxy.NodeActions.class );
final RelationshipProxy.RelationshipActions relActions = mock( RelationshipProxy.RelationshipActions.class );
- when( nodeActions.newRelationshipProxy( anyLong() ) ).thenAnswer( new Answer()
+ when( nodeActions.lazyRelationshipProxy( anyLong() ) ).thenAnswer( new Answer()
{
@Override
public RelationshipProxy answer( InvocationOnMock invocation ) throws Throwable