Skip to content

Commit

Permalink
Add access mode
Browse files Browse the repository at this point in the history
  • Loading branch information
vietj committed Feb 23, 2024
1 parent 0abeaf3 commit 957fbd4
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 51 deletions.
62 changes: 57 additions & 5 deletions src/main/java/io/vertx/core/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
import io.vertx.codegen.annotations.VertxGen;
import io.vertx.core.impl.VertxThread;
import io.vertx.core.json.JsonObject;
import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.context.locals.AccessMode;
import io.vertx.core.spi.context.locals.ContextKey;

import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -254,7 +255,9 @@ default List<String> processArgs() {
* @return the local data
*/
@GenIgnore
<T> T getLocal(ContextKey<T> key);
default <T> T getLocal(ContextKey<T> key) {
return getLocal(key, AccessMode.CONCURRENT);
}

/**
* Get some local data from the context, when it does not exist the {@code initialValueSupplier} is called to obtain
Expand All @@ -268,7 +271,9 @@ default List<String> processArgs() {
* @return the local data
*/
@GenIgnore
<T> T getLocal(ContextKey<T> key, Supplier<? extends T> initialValueSupplier);
default <T> T getLocal(ContextKey<T> key, Supplier<? extends T> initialValueSupplier) {
return getLocal(key, AccessMode.CONCURRENT, initialValueSupplier);
}

/**
* Put some local data in the context.
Expand All @@ -279,7 +284,9 @@ default List<String> processArgs() {
* @param value the data
*/
@GenIgnore
<T> void putLocal(ContextKey<T> key, T value);
default <T> void putLocal(ContextKey<T> key, T value) {
putLocal(key, AccessMode.CONCURRENT, value);
}

/**
* Remove some local data from the context.
Expand All @@ -288,7 +295,52 @@ default List<String> processArgs() {
*/
@GenIgnore
default <T> void removeLocal(ContextKey<T> key) {
putLocal(key, null);
putLocal(key, AccessMode.CONCURRENT, null);
}

/**
* Get some local data from the context.
*
* @param key the key of the data
* @param <T> the type of the data
* @return the local data
*/
@GenIgnore
<T> T getLocal(ContextKey<T> key, AccessMode accessMode);

/**
* Get some local data from the context, when it does not exist the {@code initialValueSupplier} is called to obtain
* the initial value.
*
* <p> The {@code initialValueSupplier} might be called multiple times when multiple threads call this method concurrently.
*
* @param key the key of the data
* @param initialValueSupplier the supplier of the initial value optionally called
* @param <T> the type of the data
* @return the local data
*/
@GenIgnore
<T> T getLocal(ContextKey<T> key, AccessMode accessMode, Supplier<? extends T> initialValueSupplier);

/**
* Put some local data in the context.
* <p>
* This can be used to share data between different handlers that share a context
*
* @param key the key of the data
* @param value the data
*/
@GenIgnore
<T> void putLocal(ContextKey<T> key, AccessMode accessMode, T value);

/**
* Remove some local data from the context.
*
* @param key the key to remove
*/
@GenIgnore
default <T> void removeLocal(ContextKey<T> key, AccessMode accessMode) {
putLocal(key, accessMode, null);
}

/**
Expand Down
33 changes: 8 additions & 25 deletions src/main/java/io/vertx/core/impl/ContextBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@
*/
package io.vertx.core.impl;

import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.context.locals.AccessMode;
import io.vertx.core.spi.context.locals.ContextKey;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.Supplier;

/**
Expand All @@ -23,54 +22,38 @@
*/
class ContextBase {

private static final VarHandle LOCALS_UPDATER = MethodHandles.arrayElementVarHandle(Object[].class);

final Object[] locals;

ContextBase(Object[] locals) {
this.locals = locals;
}

public final <T> T getLocal(ContextKey<T> key) {
public final <T> T getLocal(ContextKey<T> key, AccessMode accessMode) {
ContextKeyImpl<T> internalKey = (ContextKeyImpl<T>) key;
int index = internalKey.index;
if (index >= locals.length) {
throw new IllegalArgumentException();
}
Object res = LOCALS_UPDATER.getVolatile(locals, index);
Object res = accessMode.get(locals, index);
return (T) res;
}

public final <T> T getLocal(ContextKey<T> key, Supplier<? extends T> initialValueSupplier) {
public final <T> T getLocal(ContextKey<T> key, AccessMode accessMode, Supplier<? extends T> initialValueSupplier) {
ContextKeyImpl<T> internalKey = (ContextKeyImpl<T>) key;
int index = internalKey.index;
if (index >= locals.length) {
throw new IllegalArgumentException("Invalid key index: " + index);
}
Object res;
while (true) {
res = LOCALS_UPDATER.getVolatile(locals, index);
if (res != null) {
break;
}
Object initial = initialValueSupplier.get();
if (initial == null) {
throw new IllegalStateException();
}
if (LOCALS_UPDATER.compareAndSet(locals, index, null, initial)) {
res = initial;
break;
}
}
Object res = accessMode.getOrCreate(locals, index, (Supplier<Object>) initialValueSupplier);
return (T) res;
}

public final <T> void putLocal(ContextKey<T> key, T value) {
public final <T> void putLocal(ContextKey<T> key, AccessMode accessMode, T value) {
ContextKeyImpl<T> internalKey = (ContextKeyImpl<T>) key;
int index = internalKey.index;
if (index >= locals.length) {
throw new IllegalArgumentException();
}
LOCALS_UPDATER.setRelease(locals, index, value);
accessMode.put(locals, index, value);
}
}
3 changes: 0 additions & 3 deletions src/main/java/io/vertx/core/impl/ContextImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,9 @@
import io.vertx.core.impl.logging.Logger;
import io.vertx.core.impl.logging.LoggerFactory;
import io.vertx.core.json.JsonObject;
import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.metrics.PoolMetrics;
import io.vertx.core.spi.tracing.VertxTracer;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.*;

/**
Expand Down
1 change: 0 additions & 1 deletion src/main/java/io/vertx/core/impl/ContextInternal.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import io.vertx.core.impl.future.PromiseImpl;
import io.vertx.core.impl.future.PromiseInternal;
import io.vertx.core.impl.future.SucceededFuture;
import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.tracing.VertxTracer;

import java.util.concurrent.Callable;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/vertx/core/impl/ContextKeyImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/
package io.vertx.core.impl;

import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.context.locals.ContextKey;

/**
* @author <a href="mailto:[email protected]">Julien Viet</a>
Expand Down
1 change: 0 additions & 1 deletion src/main/java/io/vertx/core/impl/DuplicatedContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import io.vertx.core.Handler;
import io.vertx.core.ThreadingModel;
import io.vertx.core.json.JsonObject;
import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.tracing.VertxTracer;

import java.util.concurrent.Callable;
Expand Down
78 changes: 78 additions & 0 deletions src/main/java/io/vertx/core/spi/context/locals/AccessMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2011-2024 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package io.vertx.core.spi.context.locals;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.Supplier;

/**
* Defines the access mode of a context locals
*/
public interface AccessMode {

/**
* This access mode provides concurrent access to context locals with thread safety and atomicity.
*/
AccessMode CONCURRENT = new AccessMode() {

private final VarHandle LOCALS_UPDATER = MethodHandles.arrayElementVarHandle(Object[].class);

@Override
public Object get(Object[] locals, int idx) {
return LOCALS_UPDATER.getVolatile(locals, idx);
}

@Override
public void put(Object[] locals, int idx, Object value) {
LOCALS_UPDATER.setRelease(locals, idx, value);
}

@Override
public Object getOrCreate(Object[] locals, int index, Supplier<Object> initialValueSupplier) {
Object res;
while (true) {
res = LOCALS_UPDATER.getVolatile(locals, index);
if (res != null) {
break;
}
Object initial = initialValueSupplier.get();
if (initial == null) {
throw new IllegalStateException();
}
if (LOCALS_UPDATER.compareAndSet(locals, index, null, initial)) {
res = initial;
break;
}
}
return res;
}
};

/**
* Return the object at index {@code idx} in the {@code locals} array.
* @param locals the array
* @param idx the index
* @return the object at {@code index}
*/
Object get(Object[] locals, int idx);

/**
* Put {@code value} in the {@code locals} array at index {@code idx}
* @param locals the array
* @param idx the index
* @param value the value
*/
void put(Object[] locals, int idx, Object value);

Object getOrCreate(Object[] locals, int index, Supplier<Object> initialValueSupplier);

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package io.vertx.core.spi.context;
package io.vertx.core.spi.context.locals;

import io.vertx.core.impl.ContextKeyImpl;

Expand Down
2 changes: 1 addition & 1 deletion src/test/java/io/vertx/core/ContextTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import io.netty.channel.EventLoop;
import io.vertx.core.impl.*;
import io.vertx.core.impl.future.PromiseInternal;
import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.context.locals.ContextKey;
import io.vertx.test.core.VertxTestBase;
import org.junit.Assume;
import org.junit.Test;
Expand Down
16 changes: 7 additions & 9 deletions src/test/java/io/vertx/core/FakeContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
import io.vertx.core.impl.VertxInternal;
import io.vertx.core.impl.WorkerPool;
import io.vertx.core.json.JsonObject;
import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.context.locals.AccessMode;
import io.vertx.core.spi.context.locals.ContextKey;
import io.vertx.core.spi.tracing.VertxTracer;

import java.util.concurrent.Callable;
Expand Down Expand Up @@ -117,22 +118,18 @@ public VertxInternal owner() {

@Override
public <T> void emit(T argument, Handler<T> task) {

}

@Override
public void execute(Runnable task) {

}

@Override
public <T> void execute(T argument, Handler<T> task) {

}

@Override
public void reportException(Throwable t) {

}

@Override
Expand Down Expand Up @@ -176,16 +173,17 @@ public CloseFuture closeFuture() {
}

@Override
public <T> T getLocal(ContextKey<T> key) {
public <T> T getLocal(ContextKey<T> key, AccessMode accessMode) {
return null;
}

@Override
public <T> void putLocal(ContextKey<T> key, T value) {
public <T> T getLocal(ContextKey<T> key, AccessMode accessMode, Supplier<? extends T> initialValueSupplier) {
return null;
}

@Override
public <T> T getLocal(ContextKey<T> key, Supplier<? extends T> initialValueSupplier) {
return null;
public <T> void putLocal(ContextKey<T> key, AccessMode accessMode, T value) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import io.vertx.core.eventbus.Message;
import io.vertx.core.eventbus.ReplyException;
import io.vertx.core.impl.ContextKeyHelper;
import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.context.locals.ContextKey;
import io.vertx.core.tracing.TracingPolicy;
import io.vertx.test.core.VertxTestBase;
import org.junit.Test;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import io.vertx.core.http.RequestOptions;
import io.vertx.core.impl.ContextInternal;
import io.vertx.core.impl.ContextKeyHelper;
import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.context.locals.ContextKey;
import io.vertx.core.spi.observability.HttpRequest;
import io.vertx.core.spi.observability.HttpResponse;
import io.vertx.core.tracing.TracingPolicy;
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/io/vertx/it/CustomContextKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import io.vertx.core.impl.VertxBuilder;
import io.vertx.core.spi.VertxServiceProvider;
import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.context.locals.ContextKey;

public class CustomContextKey implements VertxServiceProvider {

Expand Down
2 changes: 1 addition & 1 deletion src/test/java/io/vertx/test/faketracer/FakeTracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import io.vertx.core.Context;
import io.vertx.core.Vertx;
import io.vertx.core.impl.ContextKeyHelper;
import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.context.locals.ContextKey;
import io.vertx.core.spi.tracing.SpanKind;
import io.vertx.core.spi.tracing.TagExtractor;
import io.vertx.core.spi.tracing.VertxTracer;
Expand Down

0 comments on commit 957fbd4

Please sign in to comment.