提问人:James Goodall 提问时间:9/30/2023 更新时间:10/1/2023 访问量:64
如何在没有竞争条件的情况下将 ByteBufs 存储在 Caffeine LoadingCache 中?
How to store ByteBufs inside of a Caffeine LoadingCache without race conditions?
问:
我有一个从一些数据加载 Netty。一旦条目被逐出,我就需要能够释放此数据,但是存在一个竞争条件,即在我能够之前将条目逐出并且返回的条目无效。LoadingCache
ByteBuf
release()
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
有没有办法让咖啡因在获取之前安全且原子地调用保留?
答:
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
该条目将被锁定在映射中,因此其他写入将被阻止(到同一个哈希箱)。计算是原子的,因此与无锁读取相比,有一点损失,但通常应该没问题。
评论
load
PooledByteBufAllocator
ByteBuf