2

Neo4j Java API 在我调用时自动将过时的数据库更新到当前版本

new GraphDatabaseFactory().newEmbeddedDatabase(File storeDir)

我想在这样做之前检查数据库的版本。有没有办法用 Java API 做到这一点?或者:数据库版本存储在哪里,以便我可以手动读取?

4

1 回答 1

1

发布版本

我深入研究了 Neo4j API 源代码并找到了答案。debug.logNeo4j 从目录中的文件中读取之前的版本logs。每当启动数据库时,版本都会以Kernel version: (this is where you'll find the version). 例如,它可能看起来像这样:

2017-11-21 06:21:43.460+0000 INFO [o.n.k.i.DiagnosticsManager] Kernel version: 3.3.0,5b700972242a5ec3e0140261120f2845fb3520ad

你可以用 Neo4j 的方式读出 debug.log:

import java.io.File;

import org.neo4j.io.fs.DefaultFileSystemAbstraction;
import org.neo4j.io.fs.FileSystemAbstraction;
import org.neo4j.kernel.impl.transaction.log.LogTailScanner;
import org.neo4j.kernel.impl.transaction.log.PhysicalLogFile;
import org.neo4j.kernel.impl.transaction.log.PhysicalLogFiles;
import org.neo4j.kernel.impl.transaction.log.ReadableClosablePositionAwareChannel;
import org.neo4j.kernel.impl.transaction.log.entry.LogEntryReader;
import org.neo4j.kernel.impl.transaction.log.entry.LogEntryVersion;
import org.neo4j.kernel.impl.transaction.log.entry.VersionAwareLogEntryReader;

public class Neo4jVersionChecker {

    //Note that this method needs the store directory NOT the debug.log file
    public static String getNeo4jVersion(File storeDir) {   
        FileSystemAbstraction fileSystem = new DefaultFileSystemAbstraction();
        final PhysicalLogFiles logFiles = new PhysicalLogFiles( storeDir, PhysicalLogFile.DEFAULT_NAME, fileSystem );
        final LogEntryReader<ReadableClosablePositionAwareChannel> logEntryReader = new VersionAwareLogEntryReader<>();
        LogTailScanner tailScanner = new LogTailScanner( logFiles, fileSystem, logEntryReader );

        LogEntryVersion version = tailScanner.getTailInformation().latestLogEntryVersion;

        if(version!=null) {
                return version.toString();
        } else {
                return null;
        }
    }

}

上面的方法返回V3_0_10一个debug.log最新Kernel version条目是上面那个的。

不幸的是,Neo4j 的方式不是很精确。正如您Kernel version从一debug.log开始就看到的,3.3.0但 Neo 方法说它是V3_0_10. 我假设这与 Neo 在内部处理版本的方式有关。

但既然我们现在知道 Neo4j 是如何获取版本的,我们可以用更准确的方式做同样的事情:

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

import org.apache.commons.io.input.ReversedLinesFileReader;

public class VersionChecker {

    public static String getVersion(File storeDir) {
        File debugLog = new File(storeDir, "logs" + File.separator + "debug.log");
        if(debugLog.exists()) {
            try {
                //The ReversedLinesFileReader reads the last line of a file first and so on
                ReversedLinesFileReader reader = new ReversedLinesFileReader(debugLog, StandardCharsets.UTF_8);
                //Read last line
                String line = reader.readLine();
                while(line!=null) {
                    //Line can't be null at this point

                    if(line.contains("Kernel version: ")) {
                        //This line contains the version
                        line = line.substring(line.indexOf("Kernel version: ")).substring(16);  //get rid of everything except the version
                        line = line.split(",")[0];  //get rid of the second part of the Kernel version that we don't want
                        return line;
                    }

                    //Next line
                    line = reader.readLine();
                }
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}

上面的方法会返回3.3.0

商店版本

当然,这两种方法只有在有 debug.log 文件时才有效。并非所有以前的 Neo4j 版本都有它们。只要存储目录包含neostore文件,您就可以读出文件,store version它不如读出发布版本好,但至少它是一些东西。这就是它的工作原理:

有一个名为 Neo4j 的类StoreVersionCheck,其中包含一个非常方便的方法,称为getVersion(File neostoreFile). 不幸的是,我们需要一个称为 aPageCache的实例来初始化 的实例StoreVersionCheck。我们可以做一个PageCache,所以这就是我们要做的。

import java.io.File;
import java.io.IOException;
import java.util.Optional;
import java.util.function.Consumer;

import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.io.fs.DefaultFileSystemAbstraction;
import org.neo4j.io.fs.FileSystemAbstraction;
import org.neo4j.io.pagecache.PageCache;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory;
import org.neo4j.kernel.impl.pagecache.ConfiguringPageCacheFactory;
import org.neo4j.kernel.impl.storemigration.StoreVersionCheck;
import org.neo4j.kernel.impl.util.Neo4jJobScheduler;
import org.neo4j.kernel.monitoring.Monitors;
import org.neo4j.kernel.monitoring.tracing.Tracers;
import org.neo4j.logging.Log;
import org.neo4j.logging.Logger;
import org.neo4j.scheduler.JobScheduler;

public class StoreVersionChecker {

    public static String getStoreVersion(File storeDir) {
        File storeFile = new File(storeDir, "neostore");
        if(!storeFile.exists()) {
            return null;
        }
        StoreVersionCheck check = new StoreVersionCheck(buildPageCache());
        try {
            Optional<String> version = check.getVersion(storeFile);
            if(version.isPresent()) {
                return version.get();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static PageCache buildPageCache() {
        FileSystemAbstraction fileSystem = new DefaultFileSystemAbstraction();
        Config config = Config.defaults();
        Log pageCacheLog = new DummyLog();
        String desiredImplementationName = config.get( GraphDatabaseFacadeFactory.Configuration.tracer );
        Monitors monitors = new Monitors();
        JobScheduler jobScheduler = new Neo4jJobScheduler();
        Tracers tracers = new Tracers( desiredImplementationName, new DummyLog(), monitors, jobScheduler );
        ConfiguringPageCacheFactory pageCacheFactory = new ConfiguringPageCacheFactory(fileSystem, config, tracers.pageCacheTracer, tracers.pageCursorTracerSupplier, pageCacheLog );
        PageCache pageCache = pageCacheFactory.getOrCreatePageCache();

        if ( config.get( GraphDatabaseSettings.dump_configuration ) )
        {
            pageCacheFactory.dumpConfiguration();
        }
        return pageCache;
    }

    //We need this so we can give the Tracers a Log
    private static class DummyLog implements Log {

        @Override
        public boolean isDebugEnabled() {return false;}

        @Override
        public Logger debugLogger() {return null;}

        @Override
        public void debug(String message) {}

        @Override
        public void debug(String message, Throwable throwable) {}

        @Override
        public void debug(String format, Object... arguments) {}

        @Override
        public Logger infoLogger() {return null;}

        @Override
        public void info(String message) {}

        @Override
        public void info(String message, Throwable throwable) {}

        @Override
        public void info(String format, Object... arguments) {}

        @Override
        public Logger warnLogger() {return null;}

        @Override
        public void warn(String message) {}

        @Override
        public void warn(String message, Throwable throwable) {}

        @Override
        public void warn(String format, Object... arguments) {}

        @Override
        public Logger errorLogger() {return null;}

        @Override
        public void error(String message) {}

        @Override
        public void error(String message, Throwable throwable) {}

        @Override
        public void error(String format, Object... arguments) {}

        @Override
        public void bulk(Consumer<Log> consumer) {}

    }

}
于 2017-11-21T20:26:40.487 回答