MVStore文档中关于备份数据库的information有点模糊,而且我不熟悉所有的概念和术语,所以我想看看我提出的方法是否有意义。
我是一个Clojure程序员,所以请在这里原谅我的Java:
// db is an MVStore instance
FileStore fs = db.getFileStore();
FileOutputStream fos = java.io.FileOutputStream(pathToBackupFile);
FileChannel outChannel = fos.getChannel();
try {
db.commit();
db.setReuseSpace(false);
ByteBuffer bb = fs.readFully(0, fs.size());
outChannel.write(bb);
}
finally {
outChannel.close();
db.setReuseSpace(true);
}下面是它在Clojure中的样子,以防我的Java不好:
(defn backup-db
[db path-to-backup-file]
(let [fs (.getFileStore db)
backup-file (java.io.FileOutputStream. path-to-backup-file)
out-channel (.getChannel backup-file)]
(try
(.commit db)
(.setReuseSpace db false)
(let [file-contents (.readFully fs 0 (.size fs))]
(.write out-channel file-contents))
(finally
(.close out-channel)
(.setReuseSpace db true)))))我的方法似乎有效,但我想确保我没有遗漏任何东西,或者看看是否有更好的方法。谢谢!
另外,我之所以使用H2标签,是因为MVStore不存在,我也没有足够的名气来创建它。
发布于 2019-12-03 06:08:56
docs目前说:
可以随时备份持久化数据,甚至可以在写入操作期间进行备份(在线备份)。为此,首先需要禁用自动磁盘空间重用,以便始终将新数据附加到文件的末尾。然后,可以复制该文件。文件句柄可供应用程序使用。建议使用实用程序类FileChannelInputStream来执行此操作。
FileChannelInputStream和FileChannelOutputStream类将java.nio.FileChannel转换为标准的InputStream和OutputStream。BackupCommand.java中现有的H2代码展示了如何使用它们。我们可以使用Java9 input.transferTo(output);复制数据来对其进行改进:
public void backup(MVStore s, File backupFile) throws Exception {
try {
s.commit();
s.setReuseSpace(false);
try(RandomAccessFile outFile = new java.io.RandomAccessFile(backupFile, "rw");
FileChannelOutputStream output = new FileChannelOutputStream(outFile.getChannel(), false)){
try(FileChannelInputStream input = new FileChannelInputStream(s.getFileStore().getFile(), false)){
input.transferTo(output);
}
}
} finally {
s.setReuseSpace(true);
}
}请注意,当您创建FileChannelInputStream时,您必须传递false来告诉它在流关闭时不要关闭底层文件通道。如果您不这样做,它将关闭您的FileStore正在尝试使用的文件。该代码使用try-with-resource语法来确保正确关闭输出文件。
为了尝试这一点,我检查了mvstore代码,然后修改了TestMVStore,添加了一个类似于现有testSimple()代码的testBackup()方法:
private void testBackup() throws Exception {
// write some records like testSimple
String fileName = getBaseDir() + "/" + getTestName();
FileUtils.delete(fileName);
MVStore s = openStore(fileName);
MVMap<Integer, String> m = s.openMap("data");
for (int i = 0; i < 3; i++) {
m.put(i, "hello " + i);
}
// create a backup
String fileNameBackup = getBaseDir() + "/" + getTestName() + ".backup";
FileUtils.delete(fileNameBackup);
backup(s, new File(fileNameBackup));
// this throws if you accidentally close the input channel you get from the store
s.close();
// open the backup and verify
s = openStore(fileNameBackup);
m = s.openMap("data");
for (int i = 0; i < 3; i++) {
assertEquals("hello " + i, m.get(i));
}
s.close();
}在您的示例中,您正在读入一个必须放入内存的ByteBuffer。使用流transferTo方法使用当前(在Java11时)设置为8192字节的内部缓冲区。
https://stackoverflow.com/questions/49216195
复制相似问题