如何缓存文件句柄?

2022-09-04 22:45:42

我有一个应用程序想要保持打开的许多文件:定期它收到一个客户端请求,说“向文件X添加一些数据”,理想情况下,已经打开了该文件,并且已经解析了文件的标头部分,因此写入速度很快。但是,保持打开这么多文件对操作系统来说不是很好,如果我们的数据存储需求增长,则可能变得不可能。

因此,我想要一个“给我这个文件句柄,如果它没有缓存就打开”的功能,以及一些自动关闭尚未写入的文件的过程,比如说,五分钟。对于在短时间内写入的缓存文件句柄的特定情况,这可能就足够了,但这似乎是一个足够普遍的问题,应该有诸如“如果可能,从缓存中给我名为X的对象”和“我现在已经完成了对象X,所以让它有资格从现在开始驱逐五分钟”这样的函数。

core.cache看起来可能适合于此目的,但是文档非常缺乏,并且源代码没有提供有关如何使用它的特定线索。它的TTLCache看起来很有前途,但不清楚如何使用它依赖于垃圾回收来逐出项目,所以当我准备使资源过期时,我无法完全关闭它。

当然,我可以自己动手,但是有很多棘手的地方,我敢肯定我会弄错一些事情,所以我希望有人能给我指出这个功能的实现。我的代码是 clojure 的,但是当然,如果这是可以找到最佳实现的地方,那么使用 java 库是完全可以的。


答案 1

查看番石榴的缓存实现

  • 您可以为“如果句柄已缓存,则返回它,否则打开,缓存并返回它”语义的方法提供一个(或一个)CallableCacheLoaderget
  • 您可以配置定时逐出,例如 expireAfterAccess
  • 您可以注册删除管理器以在删除时关闭句柄

稍微修改链接的番石榴页面中的代码示例,使用:CacheLoader

LoadingCache<Key, Handle> graphs = CacheBuilder.newBuilder()
   .maximumSize(100) // sensible value for open handles?
   .expireAfterAccess(5, TimeUnit.MINUTES)
   .removalListener(removalListener)
   .build(
       new CacheLoader<Key, Handle>() {
         public Handle load(Key key) throws AnyException {
           return openHandle(key);
         }
       });

RemovalListener<Key, Handle> removalListener = 
  new RemovalListener<Key, Handle>() {
    public void onRemoval(RemovalNotification<Key, Handle> removal) {
      Handle h = removal.getValue();
      h.close(); // tear down properly
    }
  };

* 免责声明 *我自己没有以这种方式使用缓存,请确保您明智地测试这一点。


答案 2