All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.commandline.dbms.LoadCommand Maven / Gradle / Ivy

Go to download

This component provides management functionality and product surface for Neo4j instances.

There is a newer version: 5.23.0
Show newest version
/*
 * Copyright (c) 2002-2020 "Neo4j,"
 * Neo4j Sweden AB [http://neo4j.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.commandline.dbms;

import java.io.Closeable;
import java.io.IOException;
import java.nio.file.AccessDeniedException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.neo4j.cli.AbstractCommand;
import org.neo4j.cli.CommandFailedException;
import org.neo4j.cli.Converters;
import org.neo4j.cli.ExecutionContext;
import org.neo4j.configuration.Config;
import org.neo4j.configuration.ConfigUtils;
import org.neo4j.configuration.GraphDatabaseSettings;
import org.neo4j.configuration.helpers.NormalizedDatabaseName;
import org.neo4j.dbms.archive.IncorrectFormat;
import org.neo4j.dbms.archive.Loader;
import org.neo4j.io.layout.DatabaseLayout;
import org.neo4j.io.layout.Neo4jLayout;
import org.neo4j.kernel.internal.locker.FileLockException;

import static java.util.Objects.requireNonNull;
import static org.neo4j.commandline.Util.wrapIOException;
import static org.neo4j.configuration.GraphDatabaseSettings.DEFAULT_DATABASE_NAME;
import static org.neo4j.io.fs.FileUtils.deletePathRecursively;
import static org.neo4j.io.fs.FileUtils.deleteRecursively;
import static picocli.CommandLine.Command;
import static picocli.CommandLine.Option;

@Command(
        name = "load",
        header = "Load a database from an archive created with the dump command.",
        description = "Load a database from an archive.  must be an archive created with the dump " +
                "command.  is the name of the database to create. Existing databases can be replaced " +
                "by specifying --force. It is not possible to replace a database that is mounted in a running " +
                "Neo4j server. If --info is specified, then the database is not loaded, but information " +
                "(i.e. file count, byte count, and format of load file) about the archive is printed instead."

)
public class LoadCommand extends AbstractCommand
{
    @Option( names = "--from", required = true, paramLabel = "", description = "Path to archive created with the dump command." )
    private Path from;
    @Option( names = "--database", description = "Name of the database to load.", defaultValue = DEFAULT_DATABASE_NAME,
            converter = Converters.DatabaseNameConverter.class )
    private NormalizedDatabaseName database;
    @Option( names = "--force", arity = "0", description = "If an existing database should be replaced." )
    private boolean force;
    @Option( names = "--info", description = "Print meta-data information about the archive file, instead of loading the contained database." )
    private boolean info;

    private final Loader loader;

    public LoadCommand( ExecutionContext ctx, Loader loader )
    {
        super( ctx );
        this.loader = requireNonNull( loader );
    }

    @Override
    public void execute()
    {
        if ( info )
        {
            inspectDump();
        }
        else
        {
            loadDump();
        }
    }

    private void inspectDump()
    {
        try
        {
            Loader.DumpMetaData metaData = loader.getMetaData( from );
            ctx.out().println( "Format: " + metaData.format );
            ctx.out().println( "Files: " + metaData.fileCount );
            ctx.out().println( "Bytes: " + metaData.byteCount );
        }
        catch ( IOException e )
        {
            wrapIOException( e );
        }
    }

    private void loadDump()
    {
        Config config = buildConfig();

        DatabaseLayout databaseLayout = Neo4jLayout.of( config ).databaseLayout( database.name() );
        databaseLayout.databaseDirectory().mkdirs();
        try ( Closeable ignore = LockChecker.checkDatabaseLock( databaseLayout ) )
        {
            deleteIfNecessary( databaseLayout, force );
            load( from, databaseLayout );
        }
        catch ( FileLockException e )
        {
            throw new CommandFailedException( "The database is in use. Stop database '" + database.name() + "' and try again.", e );
        }
        catch ( IOException e )
        {
            wrapIOException( e );
        }
        catch ( CannotWriteException e )
        {
            throw new CommandFailedException( "You do not have permission to load the database.", e );
        }
    }

    private Config buildConfig()
    {
        Config cfg = Config.newBuilder()
                .fromFileNoThrow( ctx.confDir().resolve( Config.DEFAULT_CONFIG_FILE_NAME ) )
                .set( GraphDatabaseSettings.neo4j_home, ctx.homeDir() ).build();
        ConfigUtils.disableAllConnectors( cfg );
        return cfg;
    }

    private static void deleteIfNecessary( DatabaseLayout databaseLayout, boolean force )
    {
        try
        {
            if ( force )
            {
                // we remove everything except our database lock
                deletePathRecursively( databaseLayout.databaseDirectory().toPath(), path -> !path.equals( databaseLayout.databaseLockFile().toPath() ) );
                deleteRecursively( databaseLayout.getTransactionLogsDirectory() );
            }
        }
        catch ( IOException e )
        {
            wrapIOException( e );
        }
    }

    private void load( Path archive, DatabaseLayout databaseLayout )
    {
        try
        {
            loader.load( archive, databaseLayout );
        }
        catch ( NoSuchFileException e )
        {
            if ( Paths.get( e.getMessage() ).toAbsolutePath().equals( archive.toAbsolutePath() ) )
            {
                throw new CommandFailedException( "Archive does not exist: " + archive, e );
            }
            wrapIOException( e );
        }
        catch ( FileAlreadyExistsException e )
        {
            throw new CommandFailedException( "Database already exists: " + databaseLayout.getDatabaseName(), e );
        }
        catch ( AccessDeniedException e )
        {
            throw new CommandFailedException( "You do not have permission to load the database.", e );
        }
        catch ( IOException e )
        {
            wrapIOException( e );
        }
        catch ( IncorrectFormat incorrectFormat )
        {
            throw new CommandFailedException( "Not a valid Neo4j archive: " + archive, incorrectFormat );
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy