Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[9.4.x] ISPN-11285 Compute with off-heap/binary storage throws ClassCastException #8555

Merged
merged 2 commits into from Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
72 changes: 72 additions & 0 deletions core/src/main/java/org/infinispan/cache/impl/EncoderCache.java
Expand Up @@ -643,18 +643,72 @@ public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingF
return valueFromStorage(returned);
}

@Override
public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction, Metadata metadata) {
Object returned = super.compute(keyToStorage(key), wrapBiFunction(remappingFunction), metadata);
return valueFromStorage(returned);
}

@Override
public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction, long lifespan, TimeUnit lifespanUnit) {
Object returned = super.compute(keyToStorage(key), wrapBiFunction(remappingFunction), lifespan, lifespanUnit);
return valueFromStorage(returned);
}

@Override
public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
Object returned = super.compute(keyToStorage(key), wrapBiFunction(remappingFunction), lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
return valueFromStorage(returned);
}

@Override
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Object returned = super.computeIfPresent(keyToStorage(key), wrapBiFunction(remappingFunction));
return valueFromStorage(returned);
}

@Override
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction, Metadata metadata) {
Object returned = super.computeIfPresent(keyToStorage(key), wrapBiFunction(remappingFunction), metadata);
return valueFromStorage(returned);
}

@Override
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction, long lifespan, TimeUnit lifespanUnit) {
Object returned = super.computeIfPresent(keyToStorage(key), wrapBiFunction(remappingFunction), lifespan, lifespanUnit);
return valueFromStorage(returned);
}

@Override
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
Object returned = super.computeIfPresent(keyToStorage(key), wrapBiFunction(remappingFunction), lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
return valueFromStorage(returned);
}

@Override
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
Object ret = super.computeIfAbsent(keyToStorage(key), wrapFunction(mappingFunction));
return valueFromStorage(ret);
}

@Override
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction, Metadata metadata) {
Object ret = super.computeIfAbsent(keyToStorage(key), wrapFunction(mappingFunction), metadata);
return valueFromStorage(ret);
}

@Override
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction, long lifespan, TimeUnit lifespanUnit) {
Object ret = super.computeIfAbsent(keyToStorage(key), wrapFunction(mappingFunction), lifespan, lifespanUnit);
return valueFromStorage(ret);
}

@Override
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
Object ret = super.computeIfAbsent(keyToStorage(key), wrapFunction(mappingFunction), lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
return valueFromStorage(ret);
}

@Override
public V get(Object key) {
V v = super.get(keyToStorage(key));
Expand Down Expand Up @@ -696,6 +750,24 @@ public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> rem
return valueFromStorage(returned);
}

@Override
public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction, Metadata metadata) {
Object returned = super.merge(keyToStorage(key), valueToStorage(value), wrapBiFunction(remappingFunction), metadata);
return valueFromStorage(returned);
}

@Override
public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction, long lifespan, TimeUnit lifespanUnit) {
Object returned = super.merge(keyToStorage(key), valueToStorage(value), wrapBiFunction(remappingFunction), lifespan, lifespanUnit);
return valueFromStorage(returned);
}

@Override
public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
Object returned = super.merge(keyToStorage(key), valueToStorage(value), wrapBiFunction(remappingFunction), lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
return valueFromStorage(returned);
}

@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
super.forEach((k, v) -> {
Expand Down
Expand Up @@ -1494,7 +1494,7 @@ private V computeInternal(K key, BiFunction<? super K, ? super V, ? extends V> r
getDataContainer().compute(key, (k, oldEntry, factory) -> {
V oldValue = getValue(oldEntry);
V newValue = remappingFunction.apply(k, oldValue);
return getUpdatedEntry(k, oldEntry, factory, oldValue, newValue, ref, hasListeners);
return getUpdatedEntry(k, oldEntry, factory, oldValue, newValue, metadata, ref, hasListeners);
});
return notifyAndReturn(ref, hasListeners, metadata);
}
Expand Down Expand Up @@ -1527,7 +1527,7 @@ protected V mergeInternal(K key, V value, BiFunction<? super V, ? super V, ? ext
getDataContainer().compute(key, (k, oldEntry, factory) -> {
V oldValue = getValue(oldEntry);
V newValue = oldValue == null ? value : remappingFunction.apply(oldValue, value);
return getUpdatedEntry(k, oldEntry, factory, oldValue, newValue, ref, hasListeners);
return getUpdatedEntry(k, oldEntry, factory, oldValue, newValue, metadata, ref, hasListeners);
});
return notifyAndReturn(ref, hasListeners, metadata);
}
Expand All @@ -1550,7 +1550,7 @@ private V notifyAndReturn(CacheEntryChange<K, V> ref, boolean hasListeners, Meta
return newValue;
}

private InternalCacheEntry<K, V> getUpdatedEntry(K k, InternalCacheEntry<K, V> oldEntry, InternalEntryFactory factory, V oldValue, V newValue, CacheEntryChange<K, V> ref, boolean hasListeners) {
private InternalCacheEntry<K, V> getUpdatedEntry(K k, InternalCacheEntry<K, V> oldEntry, InternalEntryFactory factory, V oldValue, V newValue, Metadata metadata, CacheEntryChange<K, V> ref, boolean hasListeners) {
if (newValue == null) {
if (oldValue != null) {
if (hasListeners) {
Expand All @@ -1561,18 +1561,18 @@ private InternalCacheEntry<K, V> getUpdatedEntry(K k, InternalCacheEntry<K, V> o
return null;
} else if (oldValue == null) {
if (hasListeners) {
cacheNotifier.notifyCacheEntryCreated(k, newValue, defaultMetadata, true, ImmutableContext.INSTANCE, null);
cacheNotifier.notifyCacheEntryCreated(k, newValue, metadata, true, ImmutableContext.INSTANCE, null);
}
ref.set(k, newValue, null, null);
return factory.create(k, newValue, defaultMetadata);
return factory.create(k, newValue, metadata);
} else if (Objects.equals(oldValue, newValue)) {
return oldEntry;
} else {
if (hasListeners) {
cacheNotifier.notifyCacheEntryModified(k, newValue, defaultMetadata, oldValue, oldEntry.getMetadata(), true, ImmutableContext.INSTANCE, null);
cacheNotifier.notifyCacheEntryModified(k, newValue, metadata, oldValue, oldEntry.getMetadata(), true, ImmutableContext.INSTANCE, null);
}
ref.set(k, newValue, oldValue, oldEntry.getMetadata());
return factory.update(oldEntry, newValue, defaultMetadata);
return factory.update(oldEntry, newValue, metadata);
}
}

Expand Down
63 changes: 63 additions & 0 deletions core/src/test/java/org/infinispan/api/APINonTxTest.java
Expand Up @@ -685,6 +685,22 @@ public void testMerge() throws Exception {
}));
}

public void testMergeWithExpirationParameters() {
BiFunction<Object, Object, String> mappingFunction = (v1, v2) -> v1 + " " + v2;
cache.put("es", "hola");

assertEquals("hola guy", cache.merge("es", "guy", mappingFunction, 1_000_000, TimeUnit.SECONDS));
CacheEntry<Object, Object> entry = cache.getAdvancedCache().getCacheEntry("es");
assertEquals("hola guy", entry.getValue());
assertEquals(1_000_000_000, entry.getLifespan());


assertEquals("hola guy and good bye", cache.merge("es", "and good bye", mappingFunction, 1_100_000, TimeUnit.SECONDS, -1, TimeUnit.SECONDS));
entry = cache.getAdvancedCache().getCacheEntry("es");
assertEquals("hola guy and good bye", entry.getValue());
assertEquals(1_100_000_000, entry.getLifespan());
}

public void testForEach() {
cache.put("A", "B");
cache.put("C", "D");
Expand Down Expand Up @@ -722,6 +738,22 @@ public void testComputeIfAbsent() {
expectException(RuntimeException.class, "hi there", () -> cache.computeIfAbsent("es", functionMapsToException));
}

public void testComputeIfAbsentWithExpirationParameters() {
Function<Object, String> mappingFunction = k -> k + " world";
assertEquals("hello world", cache.computeIfAbsent("hello", mappingFunction, 1_000_000, TimeUnit.SECONDS));
CacheEntry<Object, Object> entry = cache.getAdvancedCache().getCacheEntry("hello");
assertEquals("hello world", entry.getValue());
assertEquals(1_000_000_000, entry.getLifespan());

assertEquals("hello world", cache.computeIfAbsent("hello", mappingFunction, 1_100_000, TimeUnit.SECONDS,
-1, TimeUnit.SECONDS));

entry = cache.getAdvancedCache().getCacheEntry("hello");
assertEquals("hello world", entry.getValue());
// The computeIfAbsent will fail, leaving the expiration the same
assertEquals(1_000_000_000, entry.getLifespan());
}

public void testComputeIfPresent() {
BiFunction<Object, Object, String> mappingFunction = (k, v) -> "hello_" + k + ":" + v;
cache.put("es", "hola");
Expand All @@ -744,6 +776,21 @@ public void testComputeIfPresent() {
assertNull("the key is removed", cache.get("es"));
}

public void testComputeIfPresentWithExpirationParameters() {
BiFunction<Object, Object, String> mappingFunction = (k, v) -> "hello_" + k + ":" + v;
cache.put("es", "hola");

assertEquals("hello_es:hola", cache.computeIfPresent("es", mappingFunction, 1_000_000, TimeUnit.SECONDS));
CacheEntry<Object, Object> entry = cache.getAdvancedCache().getCacheEntry("es");
assertEquals("hello_es:hola", entry.getValue());
assertEquals(1_000_000_000, entry.getLifespan());

assertEquals("hello_es:hello_es:hola", cache.computeIfPresent("es", mappingFunction, 1_100_000, TimeUnit.SECONDS, -1, TimeUnit.SECONDS));
entry = cache.getAdvancedCache().getCacheEntry("es");
assertEquals("hello_es:hello_es:hola", entry.getValue());
assertEquals(1_100_000_000, entry.getLifespan());
}

public void testCompute() {
BiFunction<Object, Object, String> mappingFunction = (k, v) -> "hello_" + k + ":" + v;
cache.put("es", "hola");
Expand Down Expand Up @@ -771,6 +818,22 @@ public void testCompute() {
expectException(RuntimeException.class, "hi there", () -> cache.compute("es", mappingToException));
}

public void testComputeWithExpirationParameters() {
BiFunction<Object, Object, String> mappingFunction = (k, v) -> "hello_" + k + ":" + v;
cache.put("es", "hola");

assertEquals("hello_es:hola", cache.compute("es", mappingFunction, 1_000_000, TimeUnit.SECONDS));
CacheEntry<Object, Object> entry = cache.getAdvancedCache().getCacheEntry("es");
assertEquals("hello_es:hola", entry.getValue());
assertEquals(1_000_000_000, entry.getLifespan());

assertEquals("hello_es:hello_es:hola", cache.compute("es", mappingFunction, 1_100_000, TimeUnit.SECONDS,
-1, TimeUnit.SECONDS));
entry = cache.getAdvancedCache().getCacheEntry("es");
assertEquals("hello_es:hello_es:hola", entry.getValue());
assertEquals(1_100_000_000, entry.getLifespan());
}

public void testReplaceAll() {
BiFunction<Object, Object, String> mappingFunction = (k, v) -> "hello_" + k + ":" + v;
cache.put("es", "hola");
Expand Down