Skip to content

Commit

Permalink
Migrate to native label index during store upgrade
Browse files Browse the repository at this point in the history
Add additional migrator participant that will create and populate
native label index as part of store upgrade if it does not exist yet.
Migrator is fully integrated into upgrade procedure: it's separate migration step
and support population progress reporting.
  • Loading branch information
MishaDemianenko committed Jul 31, 2017
1 parent c39d74a commit 2cb86ab
Show file tree
Hide file tree
Showing 8 changed files with 364 additions and 15 deletions.
Expand Up @@ -31,6 +31,7 @@
import org.neo4j.kernel.impl.storemigration.monitoring.MigrationProgressMonitor;
import org.neo4j.kernel.impl.storemigration.participant.CountsMigrator;
import org.neo4j.kernel.impl.storemigration.participant.LegacyIndexMigrator;
import org.neo4j.kernel.impl.storemigration.participant.NativeLabelScanStoreMigrator;
import org.neo4j.kernel.impl.storemigration.participant.StoreMigrator;
import org.neo4j.kernel.spi.legacyindex.IndexImplementation;
import org.neo4j.logging.LogProvider;
Expand Down Expand Up @@ -86,11 +87,13 @@ public void migrate( File storeDir )
StoreMigrationParticipant schemaMigrator = schemaIndexProvider.storeMigrationParticipant( fs, pageCache );
LegacyIndexMigrator legacyIndexMigrator = new LegacyIndexMigrator( fs, indexProviders, logProvider );
StoreMigrator storeMigrator = new StoreMigrator( fs, pageCache, config, logService );
NativeLabelScanStoreMigrator nativeLabelScanStoreMigrator = new NativeLabelScanStoreMigrator( fs, pageCache );
CountsMigrator countsMigrator = new CountsMigrator( fs, pageCache, config );

storeUpgrader.addParticipant( schemaMigrator );
storeUpgrader.addParticipant( legacyIndexMigrator );
storeUpgrader.addParticipant( storeMigrator );
storeUpgrader.addParticipant( nativeLabelScanStoreMigrator );
storeUpgrader.addParticipant( countsMigrator );
storeUpgrader.migrateIfNeeded( storeDir );
}
Expand Down
Expand Up @@ -39,8 +39,6 @@
import org.neo4j.logging.Log;
import org.neo4j.logging.LogProvider;

import static java.lang.String.format;

/**
* A migration process to migrate {@link StoreMigrationParticipant migration participants}, if there's
* need for it, before the database fully starts. Participants can
Expand Down Expand Up @@ -203,14 +201,12 @@ private void migrateToIsolatedDirectory( File storeDir, File migrationDirectory,
{
try
{
int index = 1;
for ( StoreMigrationParticipant participant : participants )
{
Section section = progressMonitor.startSection( participant.getName() );
participant.migrate( storeDir, migrationDirectory, section, versionToMigrateFrom,
upgradableDatabase.currentVersion() );
section.completed();
index++;
}
}
catch ( IOException | UncheckedIOException e )
Expand Down
@@ -0,0 +1,135 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.storemigration.participant;

import java.io.File;
import java.io.IOException;

import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
import org.neo4j.io.fs.FileSystemAbstraction;
import org.neo4j.io.pagecache.PageCache;
import org.neo4j.kernel.api.labelscan.NodeLabelUpdate;
import org.neo4j.kernel.impl.api.index.IndexStoreView;
import org.neo4j.kernel.impl.api.scan.FullLabelStream;
import org.neo4j.kernel.impl.index.labelscan.NativeLabelScanStore;
import org.neo4j.kernel.impl.store.NeoStores;
import org.neo4j.kernel.impl.store.StoreFactory;
import org.neo4j.kernel.impl.storemigration.monitoring.MigrationProgressMonitor;
import org.neo4j.kernel.impl.transaction.state.storeview.NeoStoreIndexStoreView;
import org.neo4j.kernel.lifecycle.Lifespan;
import org.neo4j.kernel.monitoring.Monitors;
import org.neo4j.logging.NullLogProvider;

import static org.neo4j.kernel.impl.locking.LockService.NO_LOCK_SERVICE;
import static org.neo4j.kernel.impl.store.format.RecordFormatSelector.selectForVersion;

public class NativeLabelScanStoreMigrator extends AbstractStoreMigrationParticipant
{
private final FileSystemAbstraction fileSystem;
private final PageCache pageCache;
private boolean nativeLabelScanStoreMigrated;

public NativeLabelScanStoreMigrator( FileSystemAbstraction fileSystem, PageCache pageCache )
{
super( "Native label scan index" );
this.fileSystem = fileSystem;
this.pageCache = pageCache;
}

@Override
public void migrate( File storeDir, File migrationDir, MigrationProgressMonitor.Section progressMonitor,
String versionToMigrateFrom, String versionToMigrateTo ) throws IOException
{
if ( migrateNativeLabelScanStore( storeDir ) )
{
StoreFactory storeFactory = getStoreFactory( storeDir, versionToMigrateFrom );
try ( NeoStores neoStores = storeFactory.openAllNeoStores();
Lifespan lifespan = new Lifespan() )
{
progressMonitor.start( neoStores.getNodeStore().getNumberOfIdsInUse() );
NativeLabelScanStore nativeLabelScanStore = getNativeLabelScanStore( migrationDir, progressMonitor, neoStores );
lifespan.add( nativeLabelScanStore );
}
nativeLabelScanStoreMigrated = true;
}
}

@Override
public void moveMigratedFiles( File migrationDir, File storeDir, String versionToUpgradeFrom,
String versionToMigrateTo ) throws IOException
{
if ( nativeLabelScanStoreMigrated )
{
File nativeLabelIndex = new File( migrationDir, NativeLabelScanStore.FILE_NAME );
fileSystem.moveToDirectory( nativeLabelIndex, storeDir );
deleteLuceneLabelIndex( getLuceneStoreDirectory( storeDir ) );
}
}

private NativeLabelScanStore getNativeLabelScanStore( File migrationDir,
MigrationProgressMonitor.Section progressMonitor, NeoStores neoStores )
{
NeoStoreIndexStoreView neoStoreIndexStoreView = new NeoStoreIndexStoreView( NO_LOCK_SERVICE, neoStores );
return new NativeLabelScanStore( pageCache, migrationDir,
new MonitoredFullLabelStream( neoStoreIndexStoreView, progressMonitor ), false, new Monitors(),
RecoveryCleanupWorkCollector.IMMEDIATE );
}

private StoreFactory getStoreFactory( File storeDir, String versionToMigrateFrom )
{
return new StoreFactory( storeDir, pageCache, fileSystem,
selectForVersion( versionToMigrateFrom ), NullLogProvider.getInstance() );
}

private boolean migrateNativeLabelScanStore( File storeDir )
{
return !fileSystem.fileExists( new File( storeDir, NativeLabelScanStore.FILE_NAME ) );
}

private void deleteLuceneLabelIndex( File indexRootDirectory ) throws IOException
{
fileSystem.deleteRecursively( indexRootDirectory );
}

private static File getLuceneStoreDirectory( File storeRootDir )
{
return new File( new File( new File( storeRootDir, "schema" ), "label" ), "lucene" );
}

private class MonitoredFullLabelStream extends FullLabelStream
{

private final MigrationProgressMonitor.Section progressMonitor;

MonitoredFullLabelStream( IndexStoreView indexStoreView, MigrationProgressMonitor.Section progressMonitor )
{
super( indexStoreView );
this.progressMonitor = progressMonitor;
}

@Override
public boolean visit( NodeLabelUpdate update ) throws IOException
{
boolean visit = super.visit( update );
progressMonitor.progress( 1 );
return visit;
}
}
}
Expand Up @@ -70,16 +70,11 @@ public void moveMigratedFiles( File migrationDir, File storeDir, String versionT
{
deleteIndexes( schemaIndexDirectory );
}
deleteIndexes( getLuceneStoreDirectory( storeDir ) );
}

private void deleteIndexes( File indexRootDirectory ) throws IOException
{
fileSystem.deleteRecursively( indexRootDirectory );
}

static File getLuceneStoreDirectory( File storeRootDir )
{
return new File( new File( new File( storeRootDir, "schema" ), "label" ), "lucene" );
}
}
Expand Up @@ -129,10 +129,6 @@
*/
public class StoreMigrator extends AbstractStoreMigrationParticipant
{
// Developers: There is a benchmark, storemigrator-benchmark, that generates large stores and benchmarks
// the upgrade process. Please utilize that when writing upgrade code to ensure the code is fast enough to
// complete upgrades in a reasonable time period.

private static final char TX_LOG_COUNTERS_SEPARATOR = 'A';
public static final String CUSTOM_IO_EXCEPTION_MESSAGE =
"Migrating this version is not supported for custom IO configurations.";
Expand Down
Expand Up @@ -58,7 +58,7 @@
*/
public class Monitors
{
public static final AtomicBoolean FALSE = new AtomicBoolean( false );
private static final AtomicBoolean FALSE = new AtomicBoolean( false );

public interface Monitor
{
Expand Down

0 comments on commit 2cb86ab

Please sign in to comment.