Skip to content

Commit cc907b4

Browse files
committed
Correctly ensure ordering via VertxServiceProvider spi + optimize interceptors
1 parent 48f27cd commit cc907b4

File tree

6 files changed

+56
-15
lines changed

6 files changed

+56
-15
lines changed

extensions/vertx/runtime/src/main/java/io/quarkus/vertx/core/runtime/QuarkusAccessModes.java

+14-4
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,37 @@
33
import java.util.concurrent.atomic.AtomicReferenceArray;
44
import java.util.function.Supplier;
55

6+
import io.vertx.core.Context;
67
import io.vertx.core.spi.context.storage.AccessMode;
78

89
final class QuarkusAccessModes {
910

11+
/**
12+
* Beware this {@link AccessMode#getOrCreate(AtomicReferenceArray, int, Supplier)} because, differently from
13+
* {@link io.vertx.core.spi.context.storage.ContextLocal#get(Context, Supplier)},
14+
* is not suitable to be used with {@link io.vertx.core.spi.context.storage.ContextLocal#get(Context, AccessMode, Supplier)}
15+
* with the same guarantees of atomicity i.e. the supplier can get called more than once by different racing threads!
16+
*/
1017
public static final AccessMode ACQUIRE_RELEASE = new AccessMode() {
1118
@Override
1219
public Object get(AtomicReferenceArray<Object> locals, int idx) {
13-
return locals.get(idx);
20+
return locals.getAcquire(idx);
1421
}
1522

1623
@Override
1724
public void put(AtomicReferenceArray<Object> locals, int idx, Object value) {
18-
locals.lazySet(idx, value);
25+
// This is still ensuring visibility across threads and happens-before,
26+
// but won't impose setVolatile total ordering i.e. StoreLoad barriers after write
27+
// to make it faster
28+
locals.setRelease(idx, value);
1929
}
2030

2131
@Override
2232
public Object getOrCreate(AtomicReferenceArray<Object> locals, int idx, Supplier<Object> initialValueSupplier) {
23-
Object value = locals.get(idx);
33+
Object value = locals.getAcquire(idx);
2434
if (value == null) {
2535
value = initialValueSupplier.get();
26-
locals.lazySet(idx, value);
36+
locals.setRelease(idx, value);
2737
}
2838
return value;
2939
}

extensions/vertx/runtime/src/main/java/io/quarkus/vertx/core/runtime/VertxLocalsHelper.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ public static void throwOnRootContextAccess() {
2424
public static <T> T getLocal(ContextInternal context, Object key) {
2525
if (VertxContext.isDuplicatedContext(context)) {
2626
// We are on a duplicated context, allow accessing the locals
27-
if (key instanceof ContextLocalImpl<?> || key instanceof ContextLocal<?>) {
27+
if (key instanceof ContextLocalImpl<?>) {
2828
var localKey = (ContextLocal<T>) key;
2929
return (T) context.getLocal(localKey, QuarkusAccessModes.ACQUIRE_RELEASE);
3030
}
31+
assert !(key instanceof ContextLocal<?>);
3132
return (T) context.localContextData().get(key);
3233
} else {
3334
throw new UnsupportedOperationException(ILLEGAL_ACCESS_TO_LOCAL_CONTEXT);
@@ -37,10 +38,11 @@ public static <T> T getLocal(ContextInternal context, Object key) {
3738
public static void putLocal(ContextInternal context, Object key, Object value) {
3839
if (VertxContext.isDuplicatedContext(context)) {
3940
// We are on a duplicated context, allow accessing the locals
40-
if (key instanceof ContextLocalImpl<?> || key instanceof ContextLocal<?>) {
41+
if (key instanceof ContextLocalImpl<?>) {
4142
var localKey = (ContextLocal<Object>) key;
4243
context.putLocal(localKey, QuarkusAccessModes.ACQUIRE_RELEASE, value);
4344
} else {
45+
assert !(key instanceof ContextLocal<?>);
4446
context.localContextData().put(key, value);
4547
}
4648
} else {
@@ -51,14 +53,15 @@ public static void putLocal(ContextInternal context, Object key, Object value) {
5153
public static boolean removeLocal(ContextInternal context, Object key) {
5254
if (VertxContext.isDuplicatedContext(context)) {
5355
// We are on a duplicated context, allow accessing the locals
54-
if (key instanceof ContextLocalImpl<?> || key instanceof ContextLocal<?>) {
56+
if (key instanceof ContextLocalImpl<?>) {
5557
var localKey = (ContextLocal<Object>) key;
5658
if (localKey == null) {
5759
return false;
5860
}
5961
context.removeLocal(localKey, QuarkusAccessModes.ACQUIRE_RELEASE);
6062
return true;
6163
}
64+
assert !(key instanceof ContextLocal<?>);
6265
return context.localContextData().remove(key) != null;
6366
} else {
6467
throw new UnsupportedOperationException(ILLEGAL_ACCESS_TO_LOCAL_CONTEXT);

extensions/vertx/runtime/src/main/java/io/quarkus/vertx/core/runtime/context/VertxContextSafetyToggle.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package io.quarkus.vertx.core.runtime.context;
22

3+
import static io.quarkus.vertx.runtime.storage.QuarkusLocalStorageKeyVertxServiceProvider.ACCESS_TOGGLE_KEY;
4+
35
import io.smallrye.common.vertx.VertxContext;
46
import io.vertx.core.Context;
57
import io.vertx.core.Vertx;
6-
import io.vertx.core.impl.ContextLocalImpl;
8+
import io.vertx.core.spi.context.storage.ContextLocal;
79

810
/**
911
* This is meant for other extensions to integrate with, to help
@@ -49,9 +51,12 @@ public final class VertxContextSafetyToggle {
4951
public static final String FULLY_DISABLE_PROPERTY = "io.quarkus.vertx.core.runtime.context.VertxContextSafetyToggle.I_HAVE_CHECKED_EVERYTHING";
5052
private static final boolean UNRESTRICTED_BY_DEFAULT = Boolean.getBoolean(UNRESTRICTED_BY_DEFAULT_PROPERTY);
5153
private static final boolean FULLY_DISABLED = Boolean.getBoolean(FULLY_DISABLE_PROPERTY);
52-
// TODO VertxImpl should be allocated AFTER getting here, to make it work!
53-
// ContextLocalImpl permanently assign a globally unique key: if the check is disabled, there's no point in creating it
54-
private static final ContextLocalImpl<Boolean> ACCESS_TOGGLE_KEY = FULLY_DISABLED ? new ContextLocalImpl<>() : null;
54+
55+
public static ContextLocal<Boolean> registerAccessToggleKey() {
56+
if (FULLY_DISABLED)
57+
return null;
58+
return ContextLocal.registerLocal(Boolean.class);
59+
}
5560

5661
/**
5762
* Verifies if the current Vert.x context was flagged as safe

extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxCurrentContextFactory.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.quarkus.vertx.runtime;
22

3+
import static io.quarkus.vertx.runtime.storage.QuarkusLocalStorageKeyVertxServiceProvider.REQUEST_SCOPED_LOCAL_KEY;
4+
35
import java.lang.annotation.Annotation;
46
import java.util.List;
57
import java.util.concurrent.ConcurrentMap;
@@ -18,13 +20,10 @@
1820
import io.vertx.core.Context;
1921
import io.vertx.core.Vertx;
2022
import io.vertx.core.impl.ContextInternal;
21-
import io.vertx.core.impl.ContextLocalImpl;
2223

2324
public class VertxCurrentContextFactory implements CurrentContextFactory {
2425

2526
private static final String LOCAL_KEY_PREFIX = "io.quarkus.vertx.cdi-current-context";
26-
// TODO VertxImpl should be allocated AFTER getting here, to make it work!
27-
private static final ContextLocalImpl<? extends ContextState> REQUEST_SCOPED_LOCAL_KEY = new ContextLocalImpl<>();
2827

2928
private final List<String> keys;
3029
private final AtomicBoolean requestScopedKeyCreated;
@@ -38,7 +37,7 @@ public VertxCurrentContextFactory() {
3837
@Override
3938
public <T extends InjectableContext.ContextState> CurrentContext<T> create(Class<? extends Annotation> scope) {
4039
if (scope == RequestScoped.class) {
41-
if (!requestScopedKeyCreated.compareAndExchange(false, true)) {
40+
if (!requestScopedKeyCreated.compareAndSet(false, true)) {
4241
throw new IllegalStateException(
4342
"Multiple current contexts for the same scope are not supported. Current context for "
4443
+ scope + " already exists!");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.quarkus.vertx.runtime.storage;
2+
3+
import io.quarkus.arc.InjectableContext;
4+
import io.quarkus.vertx.core.runtime.context.VertxContextSafetyToggle;
5+
import io.vertx.core.impl.VertxBuilder;
6+
import io.vertx.core.spi.VertxServiceProvider;
7+
import io.vertx.core.spi.context.storage.ContextLocal;
8+
9+
/**
10+
* This provider exists with the sole purpose of reliably get the optimized local keys created before
11+
* the Vertx instance is created.
12+
*/
13+
public class QuarkusLocalStorageKeyVertxServiceProvider implements VertxServiceProvider {
14+
15+
public static final ContextLocal<Boolean> ACCESS_TOGGLE_KEY = VertxContextSafetyToggle.registerAccessToggleKey();
16+
public static final ContextLocal<InjectableContext.ContextState> REQUEST_SCOPED_LOCAL_KEY = ContextLocal
17+
.registerLocal(InjectableContext.ContextState.class);
18+
19+
@Override
20+
public void init(VertxBuilder builder) {
21+
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.quarkus.vertx.runtime.storage.QuarkusLocalStorageKeyVertxServiceProvider

0 commit comments

Comments
 (0)