Skip to content

Commit

Permalink
Merge branch '8.0.x'
Browse files Browse the repository at this point in the history
* 8.0.x: (44 commits)
  💚 Putting back distroless docker image generations since gcr.io/distroless/java21-debian12 is available now
  🐛 Fix bulk post with writeMode=update does not replace the matching documents but just updates the passed properties
  ✨ Cookie based authentication
  ♻️ Use patter matching for switch in AclVarsInterpolator
  ♻️ Refactor ACLRegistry to use Predicate<Request<?>>
  ♻️ Refactor OperatorsBlacklist and GetRoleService to use ACLRegistry
  ✨ Programmatic configuration of ACLs using both allow and veto predicates
  💡 Remove reference to worker-threads in comments
  ⚰️ Remove worker-threads configuration option since RESTHeart now uses Virtual Threads
  ✨ Allow to create indexes with collation
  ✨ if no content type is specified MogoService assumes it is application/json
  ♻️ Restore blocking attribute of PingService
  ⚡ Replace Undertow's ByteBufferPool with FastByteBufferPool for Virtual Thread compatibility
  🔧 Since JIT compilation conflicts with Virtual Threads, the 'truffle-runtime' is excluded from 'restheart.jar'
  🐛 "Prevent null return in HashMapLoadingCache.getLoading() to address potential multithreading cache issue
  🥅 Handle mongodb error 241 (ConversionFailure) to return status code 400
  🐛 Add truffle-runtime to restheart.
  🐛 Fix reflect configuration for CaffeineLoadingCache
  ✅ Fix PluginsTest after PluginsScanner update
  🐛 Can build native image again. Don't use virtual threads on native image, since GraalVM still doesn't support it.
  ...
  • Loading branch information
ujibang committed Apr 19, 2024
2 parents 6805292 + 6f83acf commit 2662a3f
Show file tree
Hide file tree
Showing 106 changed files with 2,389 additions and 3,563 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/branch.yml
Expand Up @@ -32,11 +32,11 @@ jobs:
restore-keys: |
${{ runner.os }}-maven-
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
java-version: "21"

- name: Set VERSION and SHA
id: vars
Expand Down Expand Up @@ -71,7 +71,7 @@ jobs:
uses: docker/build-push-action@v4
with:
context: ./core/
platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x,linux/arm/v7
platforms: linux/amd64,linux/arm64/v8,linux/ppc64le,linux/s390x
push: true # push all images built
pull: true # pull all required images before building
tags: softinstigate/restheart-snapshot:latest,softinstigate/restheart-snapshot:${{steps.vars.outputs.SHA}}
Expand Down
4 changes: 0 additions & 4 deletions chart/values.yaml
Expand Up @@ -515,10 +515,6 @@ restHeartConfiguration:
# if <= 0, use the number of cores.
io-threads: 0

# Number of threads created for blocking tasks (such as ones involving db access). Suggested value: core*8.
# if < 0, use the number of cores * 8. With 0 working threads, blocking services won't work.
worker-threads: -1

# Use 16k buffers for best performance - as in linux 16k is generally the default amount of data that can be sent in a single write() call
# Setting to 1024 * 16 - 20; the 20 is to allow some space for getProtocol headers, see UNDERTOW-1209
buffer-size: 16364
Expand Down
4 changes: 0 additions & 4 deletions commons/pom.xml
Expand Up @@ -35,10 +35,6 @@
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-reactivestreams</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
Expand Down
Expand Up @@ -23,12 +23,17 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import com.github.benmanes.caffeine.cache.CacheLoader;
import org.restheart.utils.ThreadsUtils;

import com.github.benmanes.caffeine.cache.AsyncCacheLoader;
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;

/**
*
Expand All @@ -37,7 +42,8 @@
* @param <V> the class of the values (is Optional-ized).
*/
public class CaffeineLoadingCache<K, V> implements org.restheart.cache.LoadingCache<K, V> {
private final LoadingCache<K, Optional<V>> wrapped;
private static final Executor threadPerTaskExecutor = ThreadsUtils.virtualThreadsExecutor();
private final AsyncLoadingCache<K, Optional<V>> wrapped;

public CaffeineLoadingCache(long size, EXPIRE_POLICY expirePolicy, long ttl, Function<K, V> loader) {
var builder = Caffeine.newBuilder();
Expand All @@ -50,60 +56,79 @@ public CaffeineLoadingCache(long size, EXPIRE_POLICY expirePolicy, long ttl, Fun
builder.expireAfterAccess(ttl, TimeUnit.MILLISECONDS);
}

wrapped = builder.build(new CacheLoader<K, Optional<V>>() {
@Override
public Optional<V> load(K key) throws Exception {
return Optional.ofNullable(loader.apply(key));
}

@Override
public Map<? extends K, ? extends Optional<V>> loadAll(Set<? extends K> keys) throws Exception {
var ret = new HashMap<K, Optional<V>>();
keys.stream().forEachOrdered(key -> ret.put(key, Optional.ofNullable(loader.apply(key))));
return ret;
}
});
wrapped = builder
.executor(threadPerTaskExecutor)
.buildAsync(new AsyncCacheLoader<K, Optional<V>>() {
@Override
public CompletableFuture<? extends Optional<V>> asyncLoad(K key, Executor executor) throws Exception {
return CompletableFuture.supplyAsync(() -> Optional.ofNullable(loader.apply(key)));
}

@Override
public CompletableFuture<? extends Map<? extends K, ? extends Optional<V>>> asyncLoadAll(Set<? extends K> keys, Executor executor) throws Exception {
var ret = new HashMap<K, Optional<V>>();
keys.stream().forEachOrdered(key -> {
ret.put(key, Optional.ofNullable(loader.apply(key)));
});

return CompletableFuture.supplyAsync(() -> ret);
}
});
}

@Override
public Optional<V> get(K key) {
return wrapped.getIfPresent(key);
var cf = wrapped.getIfPresent(key);
if (cf == null) {
return null;
}

try {
return cf.get();
} catch (InterruptedException | ExecutionException ex) {
throw new RuntimeException(ex);
}
}

@Override
public synchronized Optional<V> remove(K key) {
var ret = wrapped.getIfPresent(key);
wrapped.invalidate(key);
var ret = get(key);
wrapped.synchronous().invalidate(key);
return ret;
}

@Override
public Optional<V> getLoading(K key) {
return wrapped.get(key);
var cf = wrapped.get(key);
try {
return cf.get();
} catch (InterruptedException | ExecutionException ex) {
throw new RuntimeException(ex);
}
}

@Override
public void put(K key, V value) {
wrapped.put(key, Optional.ofNullable(value));
wrapped.synchronous().put(key, Optional.ofNullable(value));
}

@Override
public void invalidate(K key) {
wrapped.invalidate(key);
wrapped.synchronous().invalidate(key);
}

@Override
public void invalidateAll() {
wrapped.invalidateAll();
wrapped.synchronous().invalidateAll();
}

@Override
public Map<K, Optional<V>> asMap() {
return wrapped.asMap();
return wrapped.synchronous().asMap();
}

@Override
public void cleanUp() {
wrapped.cleanUp();
wrapped.synchronous().cleanUp();
}
}
Expand Up @@ -411,7 +411,7 @@ private static Map<String, Object> overrideConfiguration(Map<String, Object> con
overrides.stream().forEachOrdered(o -> {
if (!silent) {
if (o.value() instanceof HashMap<?, ?> mapValue) {
var maskedValue = new HashMap<>();
var maskedValue = new HashMap<String, Object>();
mapValue.keySet().stream()
.filter(k -> k instanceof String)
.map(k -> (String) k)
Expand Down
31 changes: 14 additions & 17 deletions commons/src/main/java/org/restheart/configuration/CoreModule.java
Expand Up @@ -32,7 +32,6 @@ public record CoreModule(String name,
boolean pluginsScanningVerbose,
String baseUrl,
int ioThreads,
int workerThreads,
int bufferSize,
boolean directBuffers,
boolean forceGzipEncoding,
Expand All @@ -45,30 +44,28 @@ public record CoreModule(String name,
public static final String PLUGINS_SCANNING_VERBOSE_KEY = "plugins-scanning-verbose";
public static final String BASE_URL_KEY = "base-url";
public static final String IO_THREADS_KEY = "io-threads";
public static final String WORKER_THREADS_KEY = "worker-threads";
public static final String BUFFER_SIZE_KEY = "buffer-size";
public static final String DIRECT_BUFFERS_KEY = "direct-buffers";
public static final String FORCE_GZIP_ENCODING_KEY = "force-gzip-encoding";
public static final String ALLOW_UNESCAPED_CHARS_IN_ULR_KEY = "allow-unescaped-characters-in-url";

private static final CoreModule DEFAULT_CORE_MODULE = new CoreModule("default", "plugins", new ArrayList<>(), false, null, 0, -1, 16364, true, false, true);
private static final CoreModule DEFAULT_CORE_MODULE = new CoreModule("default", "plugins", new ArrayList<>(), false, null, 0, 16364, true, false, true);

public CoreModule(Map<String, Object> conf, boolean silent) {
this(
getOrDefault(conf, INSTANCE_NAME_KEY, DEFAULT_CORE_MODULE.name(), silent),
getOrDefault(conf, PLUGINS_DIRECTORY_PATH_KEY, DEFAULT_CORE_MODULE.pluginsDirectory(), silent),
// following is optional, so get it always in silent mode
getOrDefault(conf, PLUGINS_PACKAGES_KEY, DEFAULT_CORE_MODULE.pluginsPackages(), true),
getOrDefault(conf, PLUGINS_SCANNING_VERBOSE_KEY, false, true),
getOrDefault(conf, BASE_URL_KEY, DEFAULT_CORE_MODULE.baseUrl(), true),
getOrDefault(conf, IO_THREADS_KEY, DEFAULT_CORE_MODULE.ioThreads(), silent),
getOrDefault(conf, WORKER_THREADS_KEY, DEFAULT_CORE_MODULE.workerThreads(), silent),
getOrDefault(conf, BUFFER_SIZE_KEY, DEFAULT_CORE_MODULE.bufferSize(), silent),
getOrDefault(conf, DIRECT_BUFFERS_KEY, DEFAULT_CORE_MODULE.directBuffers(), silent),
// following is optional, so get it always in silent mode
getOrDefault(conf, FORCE_GZIP_ENCODING_KEY, DEFAULT_CORE_MODULE.forceGzipEncoding(), true),
// following is optional, so get it always in silent mode
getOrDefault(conf, ALLOW_UNESCAPED_CHARS_IN_ULR_KEY, DEFAULT_CORE_MODULE.allowUnescapedCharsInUrl(), true));
getOrDefault(conf, INSTANCE_NAME_KEY, DEFAULT_CORE_MODULE.name(), silent),
getOrDefault(conf, PLUGINS_DIRECTORY_PATH_KEY, DEFAULT_CORE_MODULE.pluginsDirectory(), silent),
// following is optional, so get it always in silent mode
getOrDefault(conf, PLUGINS_PACKAGES_KEY, DEFAULT_CORE_MODULE.pluginsPackages(), true),
getOrDefault(conf, PLUGINS_SCANNING_VERBOSE_KEY, false, true),
getOrDefault(conf, BASE_URL_KEY, DEFAULT_CORE_MODULE.baseUrl(), true),
getOrDefault(conf, IO_THREADS_KEY, DEFAULT_CORE_MODULE.ioThreads(), silent),
getOrDefault(conf, BUFFER_SIZE_KEY, DEFAULT_CORE_MODULE.bufferSize(), silent),
getOrDefault(conf, DIRECT_BUFFERS_KEY, DEFAULT_CORE_MODULE.directBuffers(), silent),
// following is optional, so get it always in silent mode
getOrDefault(conf, FORCE_GZIP_ENCODING_KEY, DEFAULT_CORE_MODULE.forceGzipEncoding(), true),
// following is optional, so get it always in silent mode
getOrDefault(conf, ALLOW_UNESCAPED_CHARS_IN_ULR_KEY, DEFAULT_CORE_MODULE.allowUnescapedCharsInUrl(), true));
}

public static CoreModule build(Map<String, Object> conf, boolean silent) {
Expand Down
Expand Up @@ -19,15 +19,18 @@
*/
package org.restheart.exchange;

import com.google.common.reflect.TypeToken;
import io.undertow.connector.PooledByteBuffer;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.Headers;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;

import org.restheart.utils.BuffersUtils;

import com.google.common.reflect.TypeToken;

import io.undertow.connector.PooledByteBuffer;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.Headers;

/**
*
* @author Andrea Di Cesare {@literal <andrea@softinstigate.com>}
Expand Down Expand Up @@ -63,6 +66,9 @@ public byte[] readContent() throws IOException {
*
* allocates the PooledByteBuffer array so close() must be invoked
* to avoid memory leaks
*
* @param content
* @throws java.io.IOException
*/
@Override
public void writeContent(byte[] content) throws IOException {
Expand Down
14 changes: 1 addition & 13 deletions commons/src/main/java/org/restheart/exchange/ExchangeKeys.java
Expand Up @@ -475,13 +475,7 @@ public enum TYPE {
/**
*
*/
TRANSACTION,

/**
* @deprecated will be removed in RH v8.0
*/
@Deprecated
METRICS
TRANSACTION
}

/**
Expand Down Expand Up @@ -682,10 +676,4 @@ public enum WRITE_MODE {
*/
UPDATE
}

/**
* @deprecated will be removed in RH v8.0
*/
@Deprecated
public static final String _METRICS = "_metrics";
}
Expand Up @@ -19,17 +19,20 @@
*/
package org.restheart.exchange;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

import org.restheart.utils.BuffersUtils;

import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;

import io.undertow.connector.PooledByteBuffer;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.Headers;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import org.restheart.utils.BuffersUtils;

/**
*
Expand Down Expand Up @@ -73,6 +76,8 @@ public JsonElement readContent() throws IOException {
*
* allocates the PooledByteBuffer array so close() must be invoked
* to avoid memory leaks
* @param content
* @throws java.io.IOException
*/
@Override
public void writeContent(JsonElement content) throws IOException {
Expand Down
20 changes: 0 additions & 20 deletions commons/src/main/java/org/restheart/exchange/MongoRequest.java
Expand Up @@ -66,7 +66,6 @@
import static org.restheart.exchange.ExchangeKeys._AGGREGATIONS;
import static org.restheart.exchange.ExchangeKeys._INDEXES;
import static org.restheart.exchange.ExchangeKeys._META;
import static org.restheart.exchange.ExchangeKeys._METRICS;
import static org.restheart.exchange.ExchangeKeys._SCHEMAS;
import static org.restheart.exchange.ExchangeKeys._SESSIONS;
import static org.restheart.exchange.ExchangeKeys._SIZE;
Expand Down Expand Up @@ -361,7 +360,6 @@ public static boolean isReservedDocumentId(TYPE type, BsonValue documentId) {
if ((type == TYPE.COLLECTION_META && sdi.startsWith(COLL_META_DOCID_PREFIX))
|| (type == TYPE.DB_META && sdi.startsWith(DB_META_DOCID))
|| (type == TYPE.BULK_DOCUMENTS && RESOURCES_WILDCARD_KEY.equals(sdi))
|| (type == TYPE.METRICS && _METRICS.equalsIgnoreCase(sdi))
|| (type == TYPE.COLLECTION_SIZE && _SIZE.equalsIgnoreCase(sdi))
|| (type == TYPE.INDEX && _INDEXES.equalsIgnoreCase(sdi))
|| (type == TYPE.COLLECTION_META && _META.equalsIgnoreCase(sdi))
Expand Down Expand Up @@ -421,8 +419,6 @@ static TYPE selectRequestType(String[] pathTokens) {
type = TYPE.TRANSACTIONS;
} else if (pathTokens.length == 5 && pathTokens[pathTokens.length - 4].equalsIgnoreCase(_SESSIONS) && pathTokens[pathTokens.length - 2].equalsIgnoreCase(_TRANSACTIONS)) {
type = TYPE.TRANSACTION;
} else if (pathTokens.length < 3 && pathTokens[1].equalsIgnoreCase(_METRICS)) {
type = TYPE.METRICS;
} else if (pathTokens.length < 3) {
type = TYPE.DB;
} else if (pathTokens.length >= 3 && pathTokens[2].endsWith(FS_FILES_SUFFIX)) {
Expand Down Expand Up @@ -452,12 +448,8 @@ static TYPE selectRequestType(String[] pathTokens) {
} else {
type = TYPE.SCHEMA;
}
} else if (pathTokens.length >= 3 && pathTokens[2].equalsIgnoreCase(_METRICS)) {
type = TYPE.METRICS;
} else if (pathTokens.length < 4) {
type = TYPE.COLLECTION;
} else if (pathTokens.length == 4 && pathTokens[3].equalsIgnoreCase(_METRICS)) {
type = TYPE.METRICS;
} else if (pathTokens.length == 4 && pathTokens[3].equalsIgnoreCase(_INDEXES)) {
type = TYPE.COLLECTION_INDEXES;
} else if (pathTokens.length == 4 && pathTokens[3].equals(RESOURCES_WILDCARD_KEY)) {
Expand Down Expand Up @@ -1480,18 +1472,6 @@ public boolean isSchemaStore() {
return getType() == TYPE.SCHEMA_STORE;
}

/**
* helper method to check request resource type
*
* @deprecated will be removed in RH v8.0
*
* @return true if type is TYPE.METRICS
*/
@Deprecated
public boolean isMetrics() {
return getType() == TYPE.METRICS;
}

/**
* helper method to check request resource type
*
Expand Down

0 comments on commit 2662a3f

Please sign in to comment.