Skip to content

Commit

Permalink
Implement batching token create for labels.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisvest committed May 22, 2018
1 parent 5187ea9 commit c88b851
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 64 deletions.
Expand Up @@ -30,6 +30,20 @@ public interface TokenWrite
*/
int labelGetOrCreateForName( String labelName ) throws IllegalTokenNameException, TooManyLabelsException;

/**
* Get or create the label token ids for each of the given {@code labelNames}, and store them at the corresponding
* index in the given {@code labelIds} array.
*
* This is effectively a batching version of {@link #labelGetOrCreateForName(String)}.
*
* @param labelNames The array of label names for which to resolve or create their id.
* @param labelIds The array into which the resulting token ids will be stored.
* @throws TooManyLabelsException if too many labels would bve created by this call, compared to the token id space
* available.
*/
void labelGetOrCreateForNames( String[] labelNames, int[] labelIds )
throws IllegalTokenNameException, TooManyLabelsException;

/**
* Creates a label with the given id
* @param labelName the name of the label
Expand Down
Expand Up @@ -68,6 +68,7 @@
import org.neo4j.internal.kernel.api.Read;
import org.neo4j.internal.kernel.api.RelationshipScanCursor;
import org.neo4j.internal.kernel.api.TokenRead;
import org.neo4j.internal.kernel.api.TokenWrite;
import org.neo4j.internal.kernel.api.Write;
import org.neo4j.internal.kernel.api.exceptions.EntityNotFoundException;
import org.neo4j.internal.kernel.api.exceptions.InvalidTransactionTypeKernelException;
Expand Down Expand Up @@ -264,9 +265,16 @@ public Node createNode( Label... labels )
{
Write write = transaction.dataWrite();
long nodeId = write.nodeCreate();
for ( Label label : labels )
TokenWrite tokenWrite = transaction.tokenWrite();
int[] labelIds = new int[labels.length];
String[] labelNames = new String[labels.length];
for ( int i = 0; i < labelNames.length; i++ )
{
labelNames[i] = labels[i].name();
}
tokenWrite.labelGetOrCreateForNames( labelNames, labelIds );
for ( int labelId : labelIds )
{
int labelId = transaction.tokenWrite().labelGetOrCreateForName( label.name() );
try
{
write.nodeAddLabel( nodeId, labelId );
Expand Down
Expand Up @@ -58,6 +58,28 @@ public int labelGetOrCreateForName( String labelName ) throws IllegalTokenNameEx
return store.labelGetOrCreateForName( labelName );
}


@Override
public void labelGetOrCreateForNames( String[] labelNames, int[] labelIds )
throws IllegalTokenNameException, TooManyLabelsException
{
ktx.assertOpen();
if ( labelNames.length != labelIds.length )
{
throw new IllegalArgumentException( "Name and id arrays have different length." );
}
for ( int i = 0; i < labelNames.length; i++ )
{
labelIds[i] = store.labelGetForName( checkValidTokenName( labelNames[i] ) );
if ( labelIds[i] == TokenHolder.NO_ID )
{
ktx.assertAllows( AccessMode::allowsTokenCreates, "Token create" );
store.labelGetOrCreateForNames( labelNames, labelIds );
return;
}
}
}

@Override
public void labelCreateForName( String labelName, int id ) throws IllegalTokenNameException, TooManyLabelsException
{
Expand Down

This file was deleted.

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2002-2018 "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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.newapi;

import org.junit.Test;

import org.neo4j.function.ThrowingAction;
import org.neo4j.internal.kernel.api.exceptions.KernelException;
import org.neo4j.internal.kernel.api.exceptions.schema.IllegalTokenNameException;
import org.neo4j.kernel.impl.api.KernelTransactionImplementation;
import org.neo4j.kernel.impl.core.TokenHolder;
import org.neo4j.storageengine.api.StoreReadLayer;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.neo4j.test.assertion.Assert.assertException;

public class KernelTokenTest
{
private final StoreReadLayer storeReadLayer = mock( StoreReadLayer.class );
private final KernelTransactionImplementation ktx = mock( KernelTransactionImplementation.class );
private KernelToken token = new KernelToken( storeReadLayer, ktx );

@Test
public void labelGetOrCreateForName() throws Exception
{
assertIllegalToken( () -> token.labelGetOrCreateForName( null ) );
assertIllegalToken( () -> token.labelGetOrCreateForName( "" ) );
when( storeReadLayer.labelGetForName( "label" ) ).thenReturn( TokenHolder.NO_ID );
when( storeReadLayer.labelGetOrCreateForName( "label" ) ).thenReturn( 42 );
assertThat( token.labelGetOrCreateForName( "label" ), is( 42 ) );
}

@Test
public void labelGetOrCreateForNames() throws Exception
{
assertIllegalToken( () -> token.labelGetOrCreateForNames( new String[]{null}, new int[1] ) );
assertIllegalToken( () -> token.labelGetOrCreateForNames( new String[]{""}, new int[1] ) );
String[] names = {"a", "b"};
int[] ids = new int[2];
when( storeReadLayer.labelGetForName( "a" ) ).thenReturn( TokenHolder.NO_ID );
token.labelGetOrCreateForNames( names, ids );
verify( storeReadLayer ).labelGetOrCreateForNames( names, ids );
}

@Test
public void propertyKeyGetOrCreateForName() throws IllegalTokenNameException
{
assertIllegalToken( () -> token.propertyKeyGetOrCreateForName( null ) );
assertIllegalToken( () -> token.propertyKeyGetOrCreateForName( "" ) );
when( storeReadLayer.propertyKeyGetForName( "prop" ) ).thenReturn( TokenHolder.NO_ID );
when( storeReadLayer.propertyKeyGetOrCreateForName( "prop" ) ).thenReturn( 42 );
assertThat( token.propertyKeyGetOrCreateForName( "prop" ), is( 42 ) );
}

@Test
public void relationshipTypeGetOrCreateForName() throws IllegalTokenNameException
{
assertIllegalToken( () -> token.relationshipTypeGetOrCreateForName( null ) );
assertIllegalToken( () -> token.relationshipTypeGetOrCreateForName( "" ) );
when( storeReadLayer.relationshipTypeGetForName( "rel" ) ).thenReturn( TokenHolder.NO_ID );
when( storeReadLayer.relationshipTypeGetOrCreateForName( "rel" ) ).thenReturn( 42 );
assertThat( token.relationshipTypeGetOrCreateForName( "rel" ), is( 42 ) );
}

private void assertIllegalToken( ThrowingAction<KernelException> f )
{
assertException( f, IllegalTokenNameException.class );
}
}

0 comments on commit c88b851

Please sign in to comment.