Использование ChronicleMap WriteContext
Рассматривая ChronicleMap (2.1.7), я не совсем понимаю, как правильно использовать WriteContext при вызове acquUsingLocked();
Сценарий, который меня интересует, - это функция, в которой мне необходимо выполнить 2 действия атомарно с точки зрения вызывающей функции. Одним из них является добавление записи на карту, если она отсутствует. Другой должен иметь место, только если ранее не было значения для данного ключа на карте.
Если ранее не было никакого значения для данного ключа в карте, и это второе действие не выполняется, карту не следует обновлять, чтобы последующие тесты не нашли значения для соответствующего ключа.
Если на карте уже есть запись для данного ключа, я не хочу обновлять ее исходное значение и не хочу предпринимать это второе действие. Но мне нужно использовать значение исходной записи, чтобы создать возвращаемое значение для вызывающей стороны.
В документации для WriteContext.created() говорится, что он возвращает true, только если запись ранее присутствовала. Если запись ранее присутствовала, возможно ли получить ссылку на предыдущее значение из контекста (или каким-либо другим способом - например, вызвать map.get() в области действия WriteContext)?
На что ссылается WriteContext.value ()? Значение предыдущей записи или потенциально обновленное значение, предоставленное мною при вызове acquUsingLocked ()?
Кроме того, если ранее на карте не было записи, и я не хочу обновлять карту, следует ли мне вызывать WriteContext.removeEntry () или WriteContext.dontPutOnClose ()?
Вот пример логики, которая мне нужна:
EntryData newValue = new EntryData();
EntryData originalValue = null;
try (WriteContext<String, EntryData> context = _map.acquireUsingLocked(key, newValue) ) {
if ( !context.created() ) {
if ( doSomething() ) {
result = createResult(newValue);
}
else {
context.removeEntry();
result = null;
}
}
else {
context.dontPutOnClose();
originalValue = context.value();
result = createResult(originalValue);
}
}
1 ответ
Если честно, разобрать твой вопрос действительно сложно.
Одним из них является добавление записи на карту, если она отсутствует.
Другой должен иметь место, только если ранее не было значения для данного ключа на карте.
Я не понимаю разницу. Для меня эти предложения синонимичны.
На что ссылается WriteContext.value ()? Значение предыдущей записи или потенциально обновленное значение, предоставленное мною при вызове acquUsingLocked ()?
writeContext.value()
всегда одинаковый (==
) к стоимости, которую вы предоставили acquireUsingLocked()
метод, newValue
в вашем примере. Это, если не возможно, некоторые RuntimeException
брошен
Кроме того, если ранее на карте не было записи, и я не хочу обновлять карту, следует ли мне вызывать WriteContext.removeEntry () или WriteContext.dontPutOnClose ()?
WriteContext.removeEntry()
потому что к тому времени acquireUsingLocked()
возвращается, запись уже внесена в карту.
метод acquireUsingLocked()
в ChronicleMap версия 2.x предназначена для двух типов значений: сгенерированное значение данных и CharSequence
, с помощью StringBuilder
,
Интерфейс сгенерированных значений данных является указателем на память вне кучи. Если acquireUsingLocked()
вызывается, когда не было записи для ключа на карте, создается новая запись, заполненная нулевыми байтами и usingValue
сделано, чтобы указывать на байты вне кучи, уже хранящиеся на карте:
try (WriteContext<K, LongValue> wc = map.acquireUsingLocked(k, value)) {
// update off-heap bytes, already serving as a value for the key
// now: k -> LongValue { 0 }
value.setValue(42);
// now: k -> LongValue { 42 }
}
В CharSequence
значение случая, когда acquireUsingLocked()
вызывается и не наблюдает никакого значения для ключа, он помещает пустую последовательность символов в ключ и устанавливает заданный StringBuilder
значение до нулевой длины: sb.setLength(0)
, Вы можете обновить значение в WriteContext
, лайк sb.append("Hello")
, когда WriteContext.close()
называется (конец блока try-with-resources), это sb
значение подбирается и помещается для запрашиваемого ключа в карту, снова. Чтобы предотвратить это, вы можете позвонить dontPutOnClose()
,
Все вышеперечисленное звучит очень неловко, поэтому в Chronicle Map 3.x вводится новая, согласованная модель "контекстов". Это не обновляет карту неявным образом, в любом случае.
try (ExternalMapQueryContext<K, V, ?> cxt = map.queryContext(key)) {
cxt.writeLock().lock();
MapEntry<K, V> entry = map.entry();
if (entry != null) {
// entry is already present in the map.
map.value.get(); // access the _previous_ value;
// value is not updated until you call:
cxt.replaceValue(entry, cxt.wrapValueAsData(newValue));
// or remove:
cxt.remove(entry);
} else {
// entry is absent.
// can insert a value using:
cxt.insert(cxt.absentEntry(), cxt.wrapValueAsData(newValue));
}
}
// no implicit inserts, removes, updates.