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 44cdbfd
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 34 deletions.
60 changes: 56 additions & 4 deletions src/main/java/io/vertx/core/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import io.vertx.codegen.annotations.VertxGen;
import io.vertx.core.impl.VertxThread;
import io.vertx.core.json.JsonObject;
import io.vertx.core.spi.context.AccessMode;
import io.vertx.core.spi.context.ContextKey;

import java.util.Collections;
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.DEFAULT);
}

/**
* 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.DEFAULT, 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.DEFAULT, 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.DEFAULT, 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
29 changes: 7 additions & 22 deletions src/main/java/io/vertx/core/impl/ContextBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*/
package io.vertx.core.impl;

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

import java.lang.invoke.MethodHandles;
Expand All @@ -23,54 +24,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);
}
}
60 changes: 60 additions & 0 deletions src/main/java/io/vertx/core/spi/context/AccessMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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;

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

public interface AccessMode {

AccessMode DEFAULT = new AccessMode() {

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

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

@Override
public void put(Object[] locals, int index, Object value) {
LOCALS_UPDATER.setRelease(locals, index, 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;
}
};

Object get(Object[] locals, int index);

void put(Object[] locals, int index, Object value);

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

}
14 changes: 6 additions & 8 deletions src/test/java/io/vertx/core/FakeContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.vertx.core.impl.VertxInternal;
import io.vertx.core.impl.WorkerPool;
import io.vertx.core.json.JsonObject;
import io.vertx.core.spi.context.AccessMode;
import io.vertx.core.spi.context.ContextKey;
import io.vertx.core.spi.tracing.VertxTracer;

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) {

}
}

0 comments on commit 44cdbfd

Please sign in to comment.