如何 运行 Jackrabbit Oak 中 Blob 存储的垃圾收集?
How to run Garabge Collection of BlobStore in Jackrabbit Oak?
使用 Oak 版本 1.42(java 17),我创建了一个由 FileBlobStore 支持的段 NodeStore,如下所示:
FileBlobStore fileBlobStore = new FileBlobStore("…");
SegmentGCOptions gcOptions = SegmentGCOptions.defaultGCOptions().setEstimationDisabled(true);
FileStore fileStore = FileStoreBuilder.
fileStoreBuilder(new File("…")).
withBlobStore(blobStore).
withGCOptions(gcOptions).
build();
Repository repository = new Jcr(new Oak(nodeStore)).createRepository()
然后,我创建了一个 blob,后来我删除了它。
与 blob 关联的文件仍在文件系统中,据我所知,需要进行垃圾回收才能真正将其删除。
运行 垃圾收集器的正确方法是什么?
通过 reading the documentation - 考虑到整个事情不在 Osgi 容器中 运行 - 看来你应该调用 MarkSweepGarbageCollector#collectGarbage(false)
,但我不清楚构造函数的参数应该是什么(或者我是否可以从其他数据结构中获取对实例的引用)——例如:
MarkSweepGarbageCollector garbageCollector = new MarkSweepGarbageCollector(
new SegmentBlobReferenceRetriever(fileStore),
blobStore,
executor,
"some path…",
10, // do not have any idea of what this parameter is and what is supposed to be set
1, // are these millis? Or millis from epoch? No idea…
null) // no idea what it is this - but it's allowed to be null
这样 blob 不会被删除 - 一点也不奇怪,因为我不清楚参数到底是什么,以及某些阶段的确切 purpose/meaning(例如 blob 被“标记”,但我无法找出这个“标记”的含义 - 即使通过查看代码......)。
我也曾尝试在 collectGarbage
之前调用 fileStore.fullGC();
(认为 可能 blob 是'由于一些“陈旧”数据而被删除),但没有运气。
也许 blob 没有被删除,因为它在版本历史记录中被引用?
如果是这样,删除 blob 的正确方法是什么 - 首先删除版本历史记录(如何?)然后 运行 垃圾收集?
我做了更多的调查,我还创建了一个小程序来复制这个问题:
- 你可以找到程序here on github
- 通过逐步执行程序流程,imo 的问题是,在“标记”阶段(即当 GC 查找实际上仍在“使用中”的 blob 时),已删除的 blob引用仍然存在,即它仍然存在于
BinaryReferencesIndex
中;因此,它是标记的,因此,开始既标记又可用,它甚至不被认为是扫荡的“候选人”。
我认为这可能与我添加 blob 的方式有关:代码如下,请参阅上面的 github 以获得完整的上下文:
Node rootFolder = session.getRootNode();
Node fileNode = rootFolder.addNode(temporaryFile.getName(), "nt:file");
fileNode.addMixin("mix:referenceable");
Node fileContentNode = fileNode.addNode("jcr:content", "nt:resource");
fileContentNode.setProperty("jcr:data", "");
session.save();
Blob blob = nodeStore.createBlob(FileUtils.openInputStream(temporaryFile));
NodeBuilder rootBuilder = nodeStore.getRoot().builder();
NodeBuilder fileContentNodeBuilder = getNodeBuilder(fileContentNode, rootBuilder);
fileContentNodeBuilder.setProperty("jcr:data", blob);
nodeStore.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
session.save();
目前,我最好的猜测是这是一个错误。
错误已 filed here。
Oak 的开发人员在上述问题中发表了评论,结果证明这不是错误,但是,为了使 GC 有效,它需要一个“紧凑”的操作 运行 首先,这样:
for (int k = 0; k < gcOptions.getRetainedGenerations(); k++) {
fileStore.compactFull();
}
使用 Oak 版本 1.42(java 17),我创建了一个由 FileBlobStore 支持的段 NodeStore,如下所示:
FileBlobStore fileBlobStore = new FileBlobStore("…");
SegmentGCOptions gcOptions = SegmentGCOptions.defaultGCOptions().setEstimationDisabled(true);
FileStore fileStore = FileStoreBuilder.
fileStoreBuilder(new File("…")).
withBlobStore(blobStore).
withGCOptions(gcOptions).
build();
Repository repository = new Jcr(new Oak(nodeStore)).createRepository()
然后,我创建了一个 blob,后来我删除了它。
与 blob 关联的文件仍在文件系统中,据我所知,需要进行垃圾回收才能真正将其删除。
运行 垃圾收集器的正确方法是什么?
通过 reading the documentation - 考虑到整个事情不在 Osgi 容器中 运行 - 看来你应该调用 MarkSweepGarbageCollector#collectGarbage(false)
,但我不清楚构造函数的参数应该是什么(或者我是否可以从其他数据结构中获取对实例的引用)——例如:
MarkSweepGarbageCollector garbageCollector = new MarkSweepGarbageCollector(
new SegmentBlobReferenceRetriever(fileStore),
blobStore,
executor,
"some path…",
10, // do not have any idea of what this parameter is and what is supposed to be set
1, // are these millis? Or millis from epoch? No idea…
null) // no idea what it is this - but it's allowed to be null
这样 blob 不会被删除 - 一点也不奇怪,因为我不清楚参数到底是什么,以及某些阶段的确切 purpose/meaning(例如 blob 被“标记”,但我无法找出这个“标记”的含义 - 即使通过查看代码......)。
我也曾尝试在 collectGarbage
之前调用 fileStore.fullGC();
(认为 可能 blob 是'由于一些“陈旧”数据而被删除),但没有运气。
也许 blob 没有被删除,因为它在版本历史记录中被引用?
如果是这样,删除 blob 的正确方法是什么 - 首先删除版本历史记录(如何?)然后 运行 垃圾收集?
我做了更多的调查,我还创建了一个小程序来复制这个问题:
- 你可以找到程序here on github
- 通过逐步执行程序流程,imo 的问题是,在“标记”阶段(即当 GC 查找实际上仍在“使用中”的 blob 时),已删除的 blob引用仍然存在,即它仍然存在于
BinaryReferencesIndex
中;因此,它是标记的,因此,开始既标记又可用,它甚至不被认为是扫荡的“候选人”。
我认为这可能与我添加 blob 的方式有关:代码如下,请参阅上面的 github 以获得完整的上下文:
Node rootFolder = session.getRootNode();
Node fileNode = rootFolder.addNode(temporaryFile.getName(), "nt:file");
fileNode.addMixin("mix:referenceable");
Node fileContentNode = fileNode.addNode("jcr:content", "nt:resource");
fileContentNode.setProperty("jcr:data", "");
session.save();
Blob blob = nodeStore.createBlob(FileUtils.openInputStream(temporaryFile));
NodeBuilder rootBuilder = nodeStore.getRoot().builder();
NodeBuilder fileContentNodeBuilder = getNodeBuilder(fileContentNode, rootBuilder);
fileContentNodeBuilder.setProperty("jcr:data", blob);
nodeStore.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
session.save();
目前,我最好的猜测是这是一个错误。
错误已 filed here。
Oak 的开发人员在上述问题中发表了评论,结果证明这不是错误,但是,为了使 GC 有效,它需要一个“紧凑”的操作 运行 首先,这样:
for (int k = 0; k < gcOptions.getRetainedGenerations(); k++) {
fileStore.compactFull();
}