如何在没有竞争条件的情况下将 ByteBufs 存储在 Caffeine LoadingCache 中?

How to store ByteBufs inside of a Caffeine LoadingCache without race conditions?

提问人:James Goodall 提问时间:9/30/2023 更新时间:10/1/2023 访问量:64

问:

我有一个从一些数据加载 Netty。一旦条目被逐出,我就需要能够释放此数据,但是存在一个竞争条件,即在我能够之前将条目逐出并且返回的条目无效。LoadingCacheByteBufrelease()retain()ByteBuf

这是我尝试执行的操作的一个例子 - 当在 get 和 retain 之间调用删除侦听器时,就会发生争用。

LoadingCache<String, ByteBuf> cache = Caffeine.newBuilder()
    .maximumSize(128)
    .evictionListener(
        (RemovalListener<String, ByteBuf>) (string, buf, removalCause) -> {
            buf.release();
        }
    )
    .build(
        key -> {
            ByteBuf byteBuf = null;
            // TODO: Create the ByteBuf from a pool
            return byteBuf;
        }
    );

ByteBuf buffer = cache.get("hello").retain();

// If the entry is evicted between call to get and the retain then a race condition occurs
// That means the reference count drops to 0 before the retain is invoked

有没有办法让咖啡因在获取之前安全且原子地调用保留?

java netty 咖啡因缓存 netty4

评论

0赞 Louis Wasserman 10/1/2023
您需要保留在正文中。load
0赞 James Goodall 10/1/2023
默认情况下,@LouisWasserman提供引用计数为 1,因此保留该值会导致内存泄漏。PooledByteBufAllocatorByteBuf

答:

1赞 Ben Manes 10/1/2023 #1

可用于对条目执行读/写操作。asMap().compute

Cache<String, ByteBuf> cache = Caffeine.newBuilder()
    .evictionListener((String string, ByteBuf buf, RemovalCause cause) -> buf.release())
    .maximumSize(128)
    .build();

ByteBuf buffer = cache.asMap().compute(key, (k, buf) -> {
  if (buf == null) {
    buf = // TODO: Create the ByteBuf from a pool
  }
  buf.retain();
  return buf;
});

您可能还对固定条目的固定感兴趣,方法是指定条目消耗零容量,因此大小逐出将跳过该条目。

Cache<String, ByteBuf> cache = Caffeine.newBuilder()
    .weigher((String string, ByteBuf buf) -> (buf.refCnt() == 0) ? 1 : 0)
    .maximumWeight(128)
    .build();

public ByteBuf acquire(String key) {
  // above
}
public void release(String key) {
  cache.asMap().compute(key, (k, buf) -> {
    buf.release();
    return buf;
  });
}

评论

0赞 James Goodall 10/1/2023
谢谢 - 这是一个很好的解决方案。是否可以在计算调用期间释放缓冲区,或者密钥是否会被暂时锁定?例如,调用计算,缓冲区不是 null,但在条件 null 检查后立即释放。
0赞 Ben Manes 10/1/2023
该条目将被锁定在映射中,因此其他写入将被阻止(到同一个哈希箱)。计算是原子的,因此与无锁读取相比,有一点损失,但通常应该没问题。