Skip to content

Commit

Permalink
Make GraphPropertiesProxy use Kernel API
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusmelke committed Mar 1, 2018
1 parent 2f74c49 commit 76eb142
Showing 1 changed file with 140 additions and 71 deletions.
Expand Up @@ -20,23 +20,25 @@
package org.neo4j.kernel.impl.core;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.neo4j.collection.primitive.PrimitiveIntIterator;
import org.neo4j.graphdb.ConstraintViolationException;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.NotFoundException;
import org.neo4j.graphdb.TransactionTerminatedException;
import org.neo4j.internal.kernel.api.PropertyCursor;
import org.neo4j.internal.kernel.api.TokenRead;
import org.neo4j.internal.kernel.api.exceptions.InvalidTransactionTypeKernelException;
import org.neo4j.internal.kernel.api.exceptions.PropertyKeyIdNotFoundKernelException;
import org.neo4j.kernel.api.ReadOperations;
import org.neo4j.kernel.api.Statement;
import org.neo4j.kernel.api.StatementTokenNameLookup;
import org.neo4j.kernel.api.exceptions.PropertyNotFoundException;
import org.neo4j.internal.kernel.api.exceptions.schema.IllegalTokenNameException;
import org.neo4j.kernel.api.KernelTransaction;
import org.neo4j.kernel.api.Statement;
import org.neo4j.kernel.api.exceptions.Status;
import org.neo4j.kernel.impl.api.operations.KeyReadOperations;
import org.neo4j.storageengine.api.EntityType;
import org.neo4j.values.storable.Value;
import org.neo4j.values.storable.Values;

Expand Down Expand Up @@ -65,11 +67,23 @@ public boolean hasProperty( String key )
return false;
}

try ( Statement statement = actions.statement() )
KernelTransaction transaction = safeAcquireTransaction();
int propertyKey = transaction.tokenRead().propertyKey( key );
if ( propertyKey == KeyReadOperations.NO_SUCH_PROPERTY_KEY )
{
int propertyKeyId = statement.readOperations().propertyKeyGetForName( key );
return statement.readOperations().graphHasProperty( propertyKeyId );
return false;
}

PropertyCursor properties = transaction.propertyCursor();
transaction.dataRead().graphProperties( properties );
while ( properties.next() )
{
if ( propertyKey == properties.propertyKey() )
{
return true;
}
}
return false;
}

@Override
Expand All @@ -79,32 +93,29 @@ public Object getProperty( String key )
{
throw new IllegalArgumentException( "(null) property key is not allowed" );
}

try ( Statement statement = actions.statement() )
KernelTransaction transaction = safeAcquireTransaction();
int propertyKey = transaction.tokenRead().propertyKey( key );
if ( propertyKey == KeyReadOperations.NO_SUCH_PROPERTY_KEY )
{
try
{
int propertyKeyId = statement.readOperations().propertyKeyGetForName( key );
if ( propertyKeyId == KeyReadOperations.NO_SUCH_PROPERTY_KEY )
{
throw new NotFoundException( format( "No such property, '%s'.", key ) );
}
throw new NotFoundException( format( "No such property, '%s'.", key ) );
}

Value value = statement.readOperations().graphGetProperty( propertyKeyId );
PropertyCursor properties = transaction.propertyCursor();
transaction.dataRead().graphProperties( properties );

while ( properties.next() )
{
if ( propertyKey == properties.propertyKey() )
{
Value value = properties.propertyValue();
if ( value == Values.NO_VALUE )
{
throw new PropertyNotFoundException( propertyKeyId, EntityType.GRAPH, -1 );
throw new NotFoundException( format( "No such property, '%s'.", key ) );
}

return value.asObjectCopy();
}
catch ( PropertyNotFoundException e )
{
throw new NotFoundException(
e.getUserMessage( new StatementTokenNameLookup( statement.readOperations() ) ), e );
}
}
throw new NotFoundException( format( "No such property, '%s'.", key ) );
}

@Override
Expand All @@ -114,36 +125,43 @@ public Object getProperty( String key, Object defaultValue )
{
throw new IllegalArgumentException( "(null) property key is not allowed" );
}

try ( Statement statement = actions.statement() )
KernelTransaction transaction = safeAcquireTransaction();
PropertyCursor properties = transaction.propertyCursor();
int propertyKey = transaction.tokenRead().propertyKey( key );
if ( propertyKey == KeyReadOperations.NO_SUCH_PROPERTY_KEY )
{
return defaultValue;
}
transaction.dataRead().graphProperties( properties );
while ( properties.next() )
{
int propertyKeyId = statement.readOperations().propertyKeyGetForName( key );
Value value = statement.readOperations().graphGetProperty( propertyKeyId );
return value == Values.NO_VALUE ? defaultValue : value.asObjectCopy();
if ( propertyKey == properties.propertyKey() )
{
Value value = properties.propertyValue();
return value == Values.NO_VALUE ? defaultValue : value.asObjectCopy();
}
}
return defaultValue;
}

@Override
public void setProperty( String key, Object value )
{
try ( Statement statement = actions.statement() )
KernelTransaction transaction = safeAcquireTransaction();
int propertyKeyId;
try
{
int propertyKeyId = statement.tokenWriteOperations().propertyKeyGetOrCreateForName( key );
try
{
statement.dataWriteOperations().graphSetProperty( propertyKeyId, Values.of( value, false ) );
}
catch ( IllegalArgumentException e )
{
// Trying to set an illegal value is a critical error - fail this transaction
actions.failTransaction();
throw e;
}
propertyKeyId = transaction.tokenWrite().propertyKeyGetOrCreateForName( key );
}
catch ( IllegalTokenNameException e )
{
throw new IllegalArgumentException( format( "Invalid property key '%s'.", key ), e );
}

try ( Statement ignore = transaction.acquireStatement() )
{
transaction.dataWrite().graphSetProperty( propertyKeyId, Values.of( value, false ) );
}
catch ( InvalidTransactionTypeKernelException e )
{
throw new ConstraintViolationException( e.getMessage(), e );
Expand All @@ -153,15 +171,20 @@ public void setProperty( String key, Object value )
@Override
public Object removeProperty( String key )
{
try ( Statement statement = actions.statement() )
KernelTransaction transaction = safeAcquireTransaction();
int propertyKeyId;
try
{
int propertyKeyId = statement.tokenWriteOperations().propertyKeyGetOrCreateForName( key );
return statement.dataWriteOperations().graphRemoveProperty( propertyKeyId ).asObjectCopy();
propertyKeyId = transaction.tokenWrite().propertyKeyGetOrCreateForName( key );
}
catch ( IllegalTokenNameException e )
{
throw new IllegalArgumentException( format( "Invalid property key '%s'.", key ), e );
}
try ( Statement ignore = transaction.acquireStatement() )
{
return transaction.dataWrite().graphRemoveProperty( propertyKeyId ).asObjectCopy();
}
catch ( InvalidTransactionTypeKernelException e )
{
throw new ConstraintViolationException( e.getMessage(), e );
Expand All @@ -171,62 +194,97 @@ public Object removeProperty( String key )
@Override
public Iterable<String> getPropertyKeys()
{
try ( Statement statement = actions.statement() )
KernelTransaction transaction = safeAcquireTransaction();
List<String> keys = new ArrayList<>();
try
{
List<String> keys = new ArrayList<>();
PrimitiveIntIterator properties = statement.readOperations().graphGetPropertyKeys();
while ( properties.hasNext() )
PropertyCursor properties = transaction.propertyCursor();
TokenRead token = transaction.tokenRead();
transaction.dataRead().graphProperties( properties );
while ( properties.next() )
{
keys.add( statement.readOperations().propertyKeyGetName( properties.next() ) );
keys.add( token.propertyKeyName( properties.propertyKey() ) );
}
return keys;
}
catch ( PropertyKeyIdNotFoundKernelException e )
{
throw new IllegalStateException( "Property key retrieved through kernel API should exist.", e );
}
return keys;
}

@Override
public Map<String, Object> getProperties( String... names )
public Map<String,Object> getProperties( String... names )
{
try ( Statement statement = actions.statement() )
Objects.requireNonNull( names, "Properties keys should be not null array." );

if ( names.length == 0 )
{
Map<String, Object> properties = new HashMap<>();
ReadOperations readOperations = statement.readOperations();
for ( String name : names )
return Collections.emptyMap();
}

KernelTransaction transaction = safeAcquireTransaction();

int itemsToReturn = names.length;
Map<String,Object> properties = new HashMap<>( itemsToReturn );
TokenRead token = transaction.tokenRead();

//Find ids, note we are betting on that the number of keys
//is small enough not to use a set here.
int[] propertyIds = new int[itemsToReturn];
for ( int i = 0; i < itemsToReturn; i++ )
{
String key = names[i];
if ( key == null )
{
throw new NullPointerException( String.format( "Key %d was null", i ) );
}
propertyIds[i] = token.propertyKey( key );
}

PropertyCursor propertyCursor = transaction.propertyCursor();
transaction.dataRead().graphProperties( propertyCursor );
int propertiesToFind = itemsToReturn;
while ( propertiesToFind > 0 && propertyCursor.next() )
{
//Do a linear check if this is a property we are interested in.
int currentKey = propertyCursor.propertyKey();
for ( int i = 0; i < itemsToReturn; i++ )
{
int propertyKeyId = readOperations.propertyKeyGetForName( name );
Object value = readOperations.graphGetProperty( propertyKeyId );
if ( value != null )
if ( propertyIds[i] == currentKey )
{
properties.put( name, value );
properties.put( names[i],
propertyCursor.propertyValue().asObjectCopy() );
propertiesToFind--;
break;
}
}
return properties;
}
return properties;
}

@Override
public Map<String, Object> getAllProperties()
{
try ( Statement statement = actions.statement() )
KernelTransaction transaction = safeAcquireTransaction();
Map<String,Object> properties = new HashMap<>();

try
{
Map<String, Object> properties = new HashMap<>();
ReadOperations readOperations = statement.readOperations();
PrimitiveIntIterator propertyKeys = readOperations.graphGetPropertyKeys();
while ( propertyKeys.hasNext() )
PropertyCursor propertyCursor = transaction.propertyCursor();
TokenRead token = transaction.tokenRead();
transaction.dataRead().graphProperties( propertyCursor );
while ( propertyCursor.next() )
{
int propertyKeyId = propertyKeys.next();
properties.put( readOperations.propertyKeyGetName( propertyKeyId ),
readOperations.graphGetProperty( propertyKeyId ).asObjectCopy() );
properties.put( token.propertyKeyName( propertyCursor.propertyKey() ),
propertyCursor.propertyValue().asObjectCopy() );
}
return properties;
}
catch ( PropertyKeyIdNotFoundKernelException e )
{
throw new IllegalStateException( "Property key retrieved through kernel API should exist.", e );
}
return properties;
}

@Override
Expand All @@ -243,4 +301,15 @@ public int hashCode()
{
return actions.getGraphDatabase().hashCode();
}

private KernelTransaction safeAcquireTransaction()
{
org.neo4j.kernel.api.KernelTransaction transaction = actions.kernelTransaction();
if ( transaction.isTerminated() )
{
Status terminationReason = transaction.getReasonIfTerminated().orElse( Status.Transaction.Terminated );
throw new TransactionTerminatedException( terminationReason );
}
return transaction;
}
}

0 comments on commit 76eb142

Please sign in to comment.