Как хранить ByteBufs внутри Caffeine LoadingCache без условий гонки?

У меня есть LoadingCache, который загружает Netty ByteBuf из некоторых данных. Мне нужно иметь возможность опубликовать эти данные с помощью release() после удаления записи, однако существует состояние гонки, при котором запись удаляется до того, как я смогу retain() это сделать, и возвращаемый ByteBuf недействителен.

Вот пример того, что я пытаюсь сделать: гонка происходит, когда между получением и сохранением вызывается прослушиватель удаления.

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

Есть ли какой-нибудь способ безопасно и атомарно вызвать сохранение Caffeine перед возвращением из режима получения?

Вам необходимо сохранить в организме load.

Louis Wasserman 01.10.2023 04:18

@LouisWasserman PooledByteBufAllocator по умолчанию предоставляет ByteBuf со счетчиком ссылок 1, поэтому сохранение его может привести к утечке памяти.

James Goodall 01.10.2023 10:48
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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;
  });
}

Спасибо - это отличное решение. Возможно ли освобождение буфера во время вычислительного вызова или ключ будет временно заблокирован? Например. Вычисление вызывается, буфер не имеет значения NULL, но затем освобождается сразу после проверки условного значения NULL.

James Goodall 30.09.2023 22:58

Запись будет заблокирована на карте, поэтому другие записи будут заблокированы (в тот же хэшбин). Вычисления являются атомарными, поэтому существует небольшой штраф по сравнению с чтением без блокировки, но в целом все должно быть в порядке.

Ben Manes 01.10.2023 00:46

Другие вопросы по теме