Skip to content

Commit

Permalink
Restored test TenantTest#test2 after implementing a new method cachin…
Browse files Browse the repository at this point in the history
…g strategy in fault tolerance. (helidon-io#8832)
  • Loading branch information
spericas authored Jun 4, 2024
1 parent 0b76c6c commit 1977286
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2023 Oracle and/or its affiliates.
* Copyright (c) 2020, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,15 +18,17 @@
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.function.Supplier;

import io.helidon.common.context.Context;
Expand Down Expand Up @@ -86,7 +88,8 @@ class MethodInvoker implements FtSupplier<Object> {
* caches the FT handler as well as some additional variables. This mapping must
* be shared by all instances of this class.
*/
private static final ConcurrentHashMap<MethodStateKey, MethodState> METHOD_STATES = new ConcurrentHashMap<>();
private static final MethodStateCache METHOD_STATES = new MethodStateCache();

/**
* The method being intercepted.
*/
Expand Down Expand Up @@ -693,7 +696,7 @@ private static class MethodState {
/**
* A key used to lookup {@code MethodState} instances, which include FT handlers.
* A class loader is necessary to support multiple applications as seen in the TCKs.
* The method class in necessary given that the same method can inherited by different
* The method class in necessary given that the same method can inherit by different
* classes with different FT annotations and should not share handlers. Finally, the
* method is main part of the key.
*/
Expand Down Expand Up @@ -727,4 +730,34 @@ public int hashCode() {
return Objects.hash(classLoader, methodClass, method);
}
}

/**
* Used instead of a {@link java.util.concurrent.ConcurrentHashMap} to avoid some
* locking problems.
*/
private static class MethodStateCache {

private final ReentrantLock lock = new ReentrantLock();
private final Map<MethodStateKey, MethodState> cache = new HashMap<>();

MethodState computeIfAbsent(MethodStateKey key, Function<MethodStateKey, MethodState> function) {
lock.lock();
try {
MethodState methodState = cache.get(key);
if (methodState != null) {
return methodState;
}
MethodState newMethodState = function.apply(key);
Objects.requireNonNull(newMethodState);
cache.put(key, newMethodState);
return newMethodState;
} finally {
lock.unlock();
}
}

void clear() {
cache.clear();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.is;
Expand All @@ -47,7 +46,6 @@ public void test() throws Exception {
}

@Test
@Disabled // issue #8813
public void test2() throws Exception {
asyncCalls(() -> baseTarget.path("test2").request()
.header("x-tenant-id", "123").get(), null);
Expand Down

0 comments on commit 1977286

Please sign in to comment.