diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/CalculateDenseNodesStage.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/CalculateDenseNodesStage.java
deleted file mode 100644
index 89011def17d97..0000000000000
--- a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/CalculateDenseNodesStage.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2002-2017 "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.unsafe.impl.batchimport;
-
-import java.io.IOException;
-
-import org.neo4j.unsafe.impl.batchimport.cache.NodeRelationshipCache;
-import org.neo4j.unsafe.impl.batchimport.cache.idmapping.IdMapper;
-import org.neo4j.unsafe.impl.batchimport.input.Collector;
-import org.neo4j.unsafe.impl.batchimport.input.Input;
-import org.neo4j.unsafe.impl.batchimport.input.InputCache;
-import org.neo4j.unsafe.impl.batchimport.input.InputRelationship;
-import org.neo4j.unsafe.impl.batchimport.staging.Stage;
-import org.neo4j.unsafe.impl.batchimport.store.BatchingNeoStores;
-
-import static org.neo4j.unsafe.impl.batchimport.input.InputCache.MAIN;
-
-/**
- * Counts number of relationships per node that is going to be imported by {@link RelationshipStage} later.
- * Dense node threshold is calculated based on these counts, so that correct relationship representation can be written
- * per node. Steps:
- *
- *
- *
{@link InputIteratorBatcherStep} reading from {@link InputIterator} produced from {@link Input#relationships()}.
- *
- *
{@link InputEntityCacherStep} alternatively {@link InputCache caches} this input data
- * (all the {@link InputRelationship input relationships}) if the iterator doesn't support
- * {@link InputIterable#supportsMultiplePasses() multiple passes}.
- *
{@link RelationshipTypeCheckerStep} keeps track of all different types of all
- * {@link InputRelationship input relationships} so that the upcoming relationship import knows which
- * types to import, i.e. how to split the import.
- *
{@link RelationshipPreparationStep} looks up {@link InputRelationship#startNode() start node input id} /
- * {@link InputRelationship#endNode() end node input id} from {@link IdMapper} and attaches to the batches going
- * through because that lookup is costly and this step can be parallelized.
- *
{@link CalculateRelationshipsStep} simply counts the input relationships going through and in the
- * end sets that count as high id in relationship store, this to more predictably create secondary record units
- * for those records that require it.
- *
For each node id {@link NodeRelationshipCache#incrementCount(long) updates the node->relationship cache}
- * so that in the end we will know how many relationships each node in the import will have and hence also
- * which nodes will have a dense representation in the store.
- *
- */
-public class CalculateDenseNodesStage extends Stage
-{
- private RelationshipTypeCheckerStep typer;
-
- public CalculateDenseNodesStage( Configuration config, InputIterable relationships,
- NodeRelationshipCache cache, IdMapper idMapper,
- Collector badCollector, InputCache inputCache,
- BatchingNeoStores neoStores ) throws IOException
- {
- super( "Calculate dense nodes", config );
- add( new InputIteratorBatcherStep<>( control(), config,
- relationships.iterator(), InputRelationship.class, t -> true ) );
- if ( !relationships.supportsMultiplePasses() )
- {
- add( new InputEntityCacherStep<>( control(), config, inputCache.cacheRelationships( MAIN ) ) );
- }
- add( typer = new RelationshipTypeCheckerStep( control(), config, neoStores.getRelationshipTypeRepository() ) );
- add( new RelationshipPreparationStep( control(), config, idMapper ) );
- add( new CalculateRelationshipsStep( control(), config, neoStores.getRelationshipStore() ) );
- add( new CalculateDenseNodesStep( control(), config, cache, badCollector ) );
- }
-
- public RelationshipTypeDistribution getDistribution()
- {
- return typer.getDistribution();
- }
-}
diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/CalculateRelationshipsStep.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/CalculateRelationshipsStep.java
deleted file mode 100644
index fcddb5f46da9c..0000000000000
--- a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/CalculateRelationshipsStep.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2002-2017 "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.unsafe.impl.batchimport;
-
-import org.neo4j.kernel.impl.store.RelationshipStore;
-import org.neo4j.kernel.impl.store.record.RelationshipRecord;
-import org.neo4j.unsafe.impl.batchimport.input.InputRelationship;
-import org.neo4j.unsafe.impl.batchimport.staging.BatchSender;
-import org.neo4j.unsafe.impl.batchimport.staging.ProcessorStep;
-import org.neo4j.unsafe.impl.batchimport.staging.StageControl;
-
-/**
- * Keeps track of number of relationships to import, this to set highId in relationship store before import.
- * This is because of the way double-unit records works, so the secondary units will end up beyond this limit.
- */
-public class CalculateRelationshipsStep extends ProcessorStep>
-{
- private final RelationshipStore relationshipStore;
- private long numberOfRelationships;
-
- public CalculateRelationshipsStep( StageControl control, Configuration config, RelationshipStore relationshipStore )
- {
- super( control, "RelationshipCalculator", config, 1 );
- this.relationshipStore = relationshipStore;
- }
-
- @Override
- protected void process( Batch batch, BatchSender sender ) throws Throwable
- {
- numberOfRelationships += batch.input.length;
- sender.send( batch );
- }
-
- @Override
- protected void done()
- {
- long highestId = relationshipStore.getHighId() + numberOfRelationships;
- relationshipStore.setHighestPossibleIdInUse( highestId );
- super.done();
- }
-}
diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/CountGroupsStage.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/CountGroupsStage.java
index 3bff6fea33678..6a814ca2a6014 100644
--- a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/CountGroupsStage.java
+++ b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/CountGroupsStage.java
@@ -44,7 +44,7 @@ public CountGroupsStage( Configuration config, RecordStore( control(), config, false, store ) );
+ add( new ReadRecordsStep<>( control(), config, false, store, null ) );
add( new CountGroupsStep( control(), config, groupCache ) );
}
}
diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/NodeCountsStage.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/NodeCountsStage.java
index 8e448dcbc6aad..088958e21be73 100644
--- a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/NodeCountsStage.java
+++ b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/NodeCountsStage.java
@@ -40,7 +40,7 @@ public NodeCountsStage( Configuration config, NodeLabelsCache cache, NodeStore n
{
super( "Node counts", config );
add( new BatchFeedStep( control(), config, allIn( nodeStore, config ), nodeStore.getRecordSize() ) );
- add( new ReadRecordsStep<>( control(), config, false, nodeStore ) );
+ add( new ReadRecordsStep<>( control(), config, false, nodeStore, null ) );
add( new RecordProcessorStep<>( control(), "COUNT", config, new NodeCountsProcessor(
nodeStore, cache, highLabelId, countsUpdater ), true, additionalStatsProviders ) );
}
diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/NodeFirstGroupStage.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/NodeFirstGroupStage.java
index 7b6f32b39e63a..2a986c811db65 100644
--- a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/NodeFirstGroupStage.java
+++ b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/NodeFirstGroupStage.java
@@ -40,7 +40,7 @@ public NodeFirstGroupStage( Configuration config, RecordStore Group", config );
add( new BatchFeedStep( control(), config, allIn( groupStore, config ), groupStore.getRecordSize() ) );
- add( new ReadRecordsStep<>( control(), config, true, groupStore ) );
+ add( new ReadRecordsStep<>( control(), config, true, groupStore, null ) );
add( new NodeSetFirstGroupStep( control(), config, nodeStore, cache ) );
add( new UpdateRecordsStep<>( control(), config, nodeStore ) );
}
diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/ParallelBatchImporter.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/ParallelBatchImporter.java
index 2326dd9412fc3..025876b92df1e 100644
--- a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/ParallelBatchImporter.java
+++ b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/ParallelBatchImporter.java
@@ -25,6 +25,8 @@
import java.util.Iterator;
import java.util.function.Predicate;
+import org.neo4j.collection.primitive.Primitive;
+import org.neo4j.collection.primitive.PrimitiveIntSet;
import org.neo4j.collection.primitive.PrimitiveLongIterator;
import org.neo4j.helpers.Exceptions;
import org.neo4j.helpers.Format;
@@ -38,6 +40,7 @@
import org.neo4j.kernel.impl.store.RelationshipStore;
import org.neo4j.kernel.impl.store.format.RecordFormatSelector;
import org.neo4j.kernel.impl.store.format.RecordFormats;
+import org.neo4j.kernel.impl.store.record.RelationshipRecord;
import org.neo4j.logging.Log;
import org.neo4j.logging.NullLogProvider;
import org.neo4j.unsafe.impl.batchimport.cache.GatheringMemoryStatsVisitor;
@@ -57,6 +60,7 @@
import org.neo4j.unsafe.impl.batchimport.staging.Stage;
import org.neo4j.unsafe.impl.batchimport.stats.StatsProvider;
import org.neo4j.unsafe.impl.batchimport.store.BatchingNeoStores;
+import org.neo4j.unsafe.impl.batchimport.store.BatchingTokenRepository.BatchingRelationshipTypeTokenRepository;
import org.neo4j.unsafe.impl.batchimport.store.io.IoMonitor;
import static java.lang.Long.max;
@@ -174,8 +178,6 @@ public void doImport( Input input ) throws IOException
InputIterable nodes = input.nodes();
InputIterable relationships = input.relationships();
InputIterable cachedNodes = cachedForSure( nodes, inputCache.nodes( MAIN, true ) );
- InputIterable cachedRelationships =
- cachedForSure( relationships, inputCache.relationships( MAIN, false ) );
RelationshipStore relationshipStore = neoStore.getRelationshipStore();
@@ -198,17 +200,17 @@ public void doImport( Input input ) throws IOException
}
}
- // Stage 2 -- calculate dense node threshold
Configuration relationshipConfig =
configWithRecordsPerPageBasedBatchSize( config, neoStore.getNodeStore() );
- CalculateDenseNodesStage calculateDenseNodesStage = new CalculateDenseNodesStage(
- relationshipConfig,
- relationships, nodeRelationshipCache, idMapper, badCollector, inputCache, neoStore );
- executeStage( calculateDenseNodesStage );
+ RelationshipStage unlinkedRelationshipStage =
+ new RelationshipStage( relationshipConfig, writeMonitor, relationships, idMapper,
+ badCollector, inputCache, nodeRelationshipCache, neoStore, storeUpdateMonitor );
+ neoStore.startFlushingPageCache();
+ executeStage( unlinkedRelationshipStage );
+ neoStore.stopFlushingPageCache();
long availableMemory = maxMemory - totalMemoryUsageOf( nodeRelationshipCache, idMapper );
- importRelationships( nodeRelationshipCache, storeUpdateMonitor, neoStore, writeMonitor,
- idMapper, cachedRelationships, calculateDenseNodesStage.getDistribution(),
+ linkRelationships( nodeRelationshipCache, neoStore, unlinkedRelationshipStage.getDistribution(),
availableMemory );
// Release this potentially really big piece of cached data
@@ -283,10 +285,9 @@ private long totalMemoryUsageOf( MemoryStatsVisitor.Visitable... users )
return total.getHeapUsage() + total.getOffHeapUsage();
}
- private void importRelationships( NodeRelationshipCache nodeRelationshipCache,
- CountingStoreUpdateMonitor storeUpdateMonitor, BatchingNeoStores neoStore,
- IoMonitor writeMonitor, IdMapper idMapper, InputIterable relationships,
- RelationshipTypeDistribution typeDistribution, long freeMemoryForDenseNodeCache )
+ private void linkRelationships( NodeRelationshipCache nodeRelationshipCache,
+ BatchingNeoStores neoStore, RelationshipTypeDistribution typeDistribution,
+ long freeMemoryForDenseNodeCache )
{
// Imports the relationships from the Input. This isn't a straight forward as importing nodes,
// since keeping track of and updating heads of relationship chains in scenarios where most nodes
@@ -300,7 +301,6 @@ private void importRelationships( NodeRelationshipCache nodeRelationshipCache,
// finally there will be one Node --> Relationship and Relationship --> Relationship stage linking
// all sparse relationship chains together.
- long nextRelationshipId = 0;
Configuration relationshipConfig =
configWithRecordsPerPageBasedBatchSize( config, neoStore.getRelationshipStore() );
Configuration nodeConfig = configWithRecordsPerPageBasedBatchSize( config, neoStore.getNodeStore() );
@@ -309,7 +309,7 @@ private void importRelationships( NodeRelationshipCache nodeRelationshipCache,
Configuration groupConfig =
configWithRecordsPerPageBasedBatchSize( config, neoStore.getRelationshipGroupStore() );
- // Do multiple rounds of relationship importing. Each round fits as many relationship types
+ // Do multiple rounds of relationship linking. Each round fits as many relationship types
// as it can (comparing with worst-case memory usage and available memory).
int typesImported = 0;
int round = 0;
@@ -318,57 +318,64 @@ private void importRelationships( NodeRelationshipCache nodeRelationshipCache,
// Figure out which types we can fit in node-->relationship cache memory.
// Types go from biggest to smallest group and so towards the end there will be
// smaller and more groups per round in this loop
- Collection