如何 运行 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();
}