Neo4j Java API 在我调用时自动将过时的数据库更新到当前版本
new GraphDatabaseFactory().newEmbeddedDatabase(File storeDir)
我想在这样做之前检查数据库的版本。有没有办法用 Java API 做到这一点?或者:数据库版本存储在哪里,以便我可以手动读取?
Neo4j Java API 在我调用时自动将过时的数据库更新到当前版本
new GraphDatabaseFactory().newEmbeddedDatabase(File storeDir)
我想在这样做之前检查数据库的版本。有没有办法用 Java API 做到这一点?或者:数据库版本存储在哪里,以便我可以手动读取?
发布版本
我深入研究了 Neo4j API 源代码并找到了答案。debug.log
Neo4j 从目录中的文件中读取之前的版本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) {}
}
}