Skip to content

Commit

Permalink
Defragments relationship groups as part of import
Browse files Browse the repository at this point in the history
now that the importer has been changed to import relationships per type
it means that relationship groups will be more scattered, which will
have read queries take a hit compared to previously.

This commit introduces a relationship group defragmenter which is
written using normal batch importer stages and steps and runs as part
of import, after the relationships have been imported.
  • Loading branch information
tinwelint committed Jul 18, 2016
1 parent 517a5c1 commit a585a26
Show file tree
Hide file tree
Showing 30 changed files with 1,801 additions and 57 deletions.
Expand Up @@ -23,11 +23,12 @@

import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.kernel.impl.store.id.IdType;
import org.neo4j.kernel.impl.storemigration.StoreFile;
import org.neo4j.kernel.impl.store.counts.CountsTracker;

public enum StoreType
{
NODE_LABEL( StoreFactory.NODE_LABELS_STORE_NAME )
NODE_LABEL( StoreFile.NODE_LABEL_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
Expand All @@ -36,15 +37,15 @@ public CommonAbstractStore open( NeoStores neoStores )
GraphDatabaseSettings.label_block_size );
}
},
NODE( StoreFactory.NODE_STORE_NAME )
NODE( StoreFile.NODE_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
{
return neoStores.createNodeStore( getStoreName() );
}
},
PROPERTY_KEY_TOKEN_NAME( StoreFactory.PROPERTY_KEY_TOKEN_NAMES_STORE_NAME )
PROPERTY_KEY_TOKEN_NAME( StoreFile.PROPERTY_KEY_TOKEN_NAMES_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
Expand All @@ -53,15 +54,15 @@ public CommonAbstractStore open( NeoStores neoStores )
TokenStore.NAME_STORE_BLOCK_SIZE );
}
},
PROPERTY_KEY_TOKEN( StoreFactory.PROPERTY_KEY_TOKEN_STORE_NAME )
PROPERTY_KEY_TOKEN( StoreFile.PROPERTY_KEY_TOKEN_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
{
return neoStores.createPropertyKeyTokenStore( getStoreName() );
}
},
PROPERTY_STRING( StoreFactory.PROPERTY_STRINGS_STORE_NAME )
PROPERTY_STRING( StoreFile.PROPERTY_STRING_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
Expand All @@ -70,7 +71,7 @@ public CommonAbstractStore open( NeoStores neoStores )
GraphDatabaseSettings.string_block_size );
}
},
PROPERTY_ARRAY( StoreFactory.PROPERTY_ARRAYS_STORE_NAME )
PROPERTY_ARRAY( StoreFile.PROPERTY_ARRAY_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
Expand All @@ -79,23 +80,23 @@ public CommonAbstractStore open( NeoStores neoStores )
GraphDatabaseSettings.array_block_size );
}
},
PROPERTY( StoreFactory.PROPERTY_STORE_NAME )
PROPERTY( StoreFile.PROPERTY_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
{
return neoStores.createPropertyStore( getStoreName() );
}
},
RELATIONSHIP( StoreFactory.RELATIONSHIP_STORE_NAME )
RELATIONSHIP( StoreFile.RELATIONSHIP_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
{
return neoStores.createRelationshipStore( getStoreName() );
}
},
RELATIONSHIP_TYPE_TOKEN_NAME( StoreFactory.RELATIONSHIP_TYPE_TOKEN_NAMES_STORE_NAME )
RELATIONSHIP_TYPE_TOKEN_NAME( StoreFile.RELATIONSHIP_TYPE_TOKEN_NAMES_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
Expand All @@ -104,15 +105,15 @@ public CommonAbstractStore open( NeoStores neoStores )
TokenStore.NAME_STORE_BLOCK_SIZE );
}
},
RELATIONSHIP_TYPE_TOKEN( StoreFactory.RELATIONSHIP_TYPE_TOKEN_STORE_NAME )
RELATIONSHIP_TYPE_TOKEN( StoreFile.RELATIONSHIP_TYPE_TOKEN_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
{
return neoStores.createRelationshipTypeTokenStore( getStoreName() );
}
},
LABEL_TOKEN_NAME( StoreFactory.LABEL_TOKEN_NAMES_STORE_NAME )
LABEL_TOKEN_NAME( StoreFile.LABEL_TOKEN_NAMES_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
Expand All @@ -121,36 +122,36 @@ public CommonAbstractStore open( NeoStores neoStores )
TokenStore.NAME_STORE_BLOCK_SIZE );
}
},
LABEL_TOKEN( StoreFactory.LABEL_TOKEN_STORE_NAME )
LABEL_TOKEN( StoreFile.LABEL_TOKEN_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
{
return neoStores.createLabelTokenStore( getStoreName() );
}
},
SCHEMA( StoreFactory.SCHEMA_STORE_NAME )
SCHEMA( StoreFile.SCHEMA_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
{
return neoStores.createSchemaStore( getStoreName() );
}
},
RELATIONSHIP_GROUP( StoreFactory.RELATIONSHIP_GROUP_STORE_NAME )
RELATIONSHIP_GROUP( StoreFile.RELATIONSHIP_GROUP_STORE )
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
{
return neoStores.createRelationshipGroupStore( getStoreName() );
}
},
COUNTS( StoreFactory.COUNTS_STORE, false )
COUNTS( null, false )
{
@Override
public CountsTracker open( final NeoStores neoStores )
{
return neoStores.createCountStore( getStoreName() );
return neoStores.createCountStore( StoreFactory.COUNTS_STORE );
}

@Override
Expand All @@ -165,8 +166,14 @@ void close( NeoStores me, Object object )
throw new UnderlyingStorageException( e );
}
}

@Override
public String getStoreName()
{
return StoreFactory.COUNTS_STORE;
}
},
META_DATA( MetaDataStore.DEFAULT_NAME ) // Make sure this META store is last
META_DATA( StoreFile.NEO_STORE ) // Make sure this META store is last
{
@Override
public CommonAbstractStore open( NeoStores neoStores )
Expand All @@ -176,16 +183,16 @@ public CommonAbstractStore open( NeoStores neoStores )
};

private final boolean recordStore;
private final String storeName;
private final StoreFile storeFile;

StoreType( String storeName )
StoreType( StoreFile storeFile )
{
this( storeName, true );
this( storeFile, true );
}

StoreType( String storeName, boolean recordStore )
StoreType( StoreFile storeFile, boolean recordStore )
{
this.storeName = storeName;
this.storeFile = storeFile;
this.recordStore = recordStore;
}

Expand All @@ -198,7 +205,12 @@ public boolean isRecordStore()

public String getStoreName()
{
return storeName;
return storeFile.fileNamePart();
}

public StoreFile getStoreFile()
{
return storeFile;
}

void close( NeoStores me, Object object )
Expand Down
Expand Up @@ -202,6 +202,11 @@ public String storeFileName()
return fileName( StoreFileType.STORE );
}

public String fileNamePart()
{
return storeFileNamePart;
}

public boolean isRecordStore()
{
return recordStore;
Expand Down
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2002-2016 "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.unsafe.impl.batchimport;

import org.neo4j.kernel.impl.store.record.RelationshipGroupRecord;
import org.neo4j.unsafe.impl.batchimport.staging.BatchSender;
import org.neo4j.unsafe.impl.batchimport.staging.Configuration;
import org.neo4j.unsafe.impl.batchimport.staging.ProcessorStep;
import org.neo4j.unsafe.impl.batchimport.staging.StageControl;

/**
* Caches {@link RelationshipGroupRecord} into {@link RelationshipGroupCache}.
*/
public class CacheGroupsStep extends ProcessorStep<RelationshipGroupRecord[]>
{
private final RelationshipGroupCache cache;

public CacheGroupsStep( StageControl control, Configuration config, RelationshipGroupCache cache )
{
super( control, "CACHE", config, 1 );
this.cache = cache;
}

@Override
protected void process( RelationshipGroupRecord[] batch, BatchSender sender ) throws Throwable
{
for ( RelationshipGroupRecord groupRecord : batch )
{
cache.put( groupRecord );
}
}
}
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2002-2016 "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.unsafe.impl.batchimport;

import org.neo4j.kernel.impl.store.RecordStore;
import org.neo4j.kernel.impl.store.record.RelationshipGroupRecord;
import org.neo4j.unsafe.impl.batchimport.staging.Configuration;
import org.neo4j.unsafe.impl.batchimport.staging.ReadRecordsStep;
import org.neo4j.unsafe.impl.batchimport.staging.Stage;
import org.neo4j.unsafe.impl.batchimport.store.BatchingNeoStores;

/**
* Stage for counting groups per node, populates {@link RelationshipGroupCache}.
*/
public class CountGroupsStage extends Stage
{
public CountGroupsStage( Configuration config, BatchingNeoStores neoStore, RelationshipGroupCache groupCache )
{
super( "Count groups", config );

RecordStore<RelationshipGroupRecord> store = neoStore.getRelationshipGroupStore();
add( new ReadRecordsStep<>( control(), config, store, RecordIdIteration.allIn( store ) ) );
add( new CountGroupsStep( control(), config, groupCache ) );
}
}
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2002-2016 "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.unsafe.impl.batchimport;

import org.neo4j.kernel.impl.store.record.RelationshipGroupRecord;
import org.neo4j.unsafe.impl.batchimport.staging.BatchSender;
import org.neo4j.unsafe.impl.batchimport.staging.Configuration;
import org.neo4j.unsafe.impl.batchimport.staging.ProcessorStep;
import org.neo4j.unsafe.impl.batchimport.staging.StageControl;

/**
* After this step is {@link #done()} all BOTH ID fields in the rel group cache will contain,
* for each node, the absolute number of groups from node 0 up to this point there is.
*/
public class CountGroupsStep extends ProcessorStep<RelationshipGroupRecord[]>
{
private final RelationshipGroupCache cache;

public CountGroupsStep( StageControl control, Configuration config, RelationshipGroupCache groupCache )
{
super( control, "COUNT", config, 1 );
this.cache = groupCache;
}

@Override
protected void process( RelationshipGroupRecord[] batch, BatchSender sender ) throws Throwable
{
for ( RelationshipGroupRecord group : batch )
{
cache.incrementGroupCount( group.getOwningNode() );
}
}
}

0 comments on commit a585a26

Please sign in to comment.