Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert synchronized to use semaphores #4284

Merged
merged 6 commits into from
Jun 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates.
* Copyright (c) 2021, 2022 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 Down Expand Up @@ -47,6 +47,9 @@
import java.util.Queue;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;

import com.google.protobuf.Any;
import com.google.protobuf.DescriptorProtos;
Expand Down Expand Up @@ -88,7 +91,7 @@
*/
public final class ProtoReflectionService extends ServerReflectionGrpc.ServerReflectionImplBase {

private final Object lock = new Object();
private final Lock indexAccess = new ReentrantLock(true);

private final Map<Server, ServerReflectionIndex> serverReflectionIndexes = new WeakHashMap<>();

Expand All @@ -110,7 +113,7 @@ public static BindableService newInstance() {
* mutable services or a change in the service names.
*/
private ServerReflectionIndex getRefreshedIndex() {
synchronized (lock) {
return accessIndex(() -> {
tjquinno marked this conversation as resolved.
Show resolved Hide resolved
Server server = InternalServer.SERVER_CONTEXT_KEY.get();
ServerReflectionIndex index = serverReflectionIndexes.get(server);
if (index == null) {
Expand Down Expand Up @@ -147,7 +150,7 @@ private ServerReflectionIndex getRefreshedIndex() {
}

return index;
}
});
}

@Override
Expand Down Expand Up @@ -594,4 +597,13 @@ private void processExtension(FieldDescriptor extension, FileDescriptor fd) {
fileDescriptorsByExtensionAndNumber.get(extensionName).put(extensionNumber, fd);
}
}

private <T> T accessIndex(Supplier<T> operation) {
indexAccess.lock();
try {
return operation.get();
} finally {
indexAccess.unlock();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2021 Oracle and/or its affiliates.
* Copyright (c) 2019, 2022 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 @@ -24,6 +24,8 @@
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
Expand Down Expand Up @@ -511,9 +513,21 @@ public void update(ServiceDescriptor.Rules rules) {
*/
private static class SynchronizedObserver<T>
extends TestStreamObserver<T> {

private final Lock nextAccess = new ReentrantLock(true);

@Override
public synchronized void onNext(T t) {
super.onNext(t);
public void onNext(T t) {
accessNext(() -> super.onNext(t));
}

private void accessNext(Runnable operation) {
nextAccess.lock();
try {
operation.run();
} finally {
nextAccess.unlock();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates.
* Copyright (c) 2021, 2022 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 @@ -16,6 +16,9 @@
package io.helidon.metrics.api;

import java.util.ServiceLoader;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand Down Expand Up @@ -83,6 +86,8 @@ private static RegistryFactoryProvider loadRegistryFactoryProvider() {
return provider;
}

private static final Lock SETTINGS_ACCESS = new ReentrantLock(true);

private RegistryFactoryManager() {
}

Expand All @@ -105,21 +110,34 @@ static RegistryFactory getInstance() {
return INSTANCE.get();
}

static synchronized RegistryFactory getInstance(MetricsSettings metricsSettings) {
RegistryFactoryManager.metricsSettings = metricsSettings;
RegistryFactory result = INSTANCE.get();
result.update(metricsSettings);
return result;
static RegistryFactory getInstance(MetricsSettings metricsSettings) {

return accessMetricsSettings(() -> {
RegistryFactoryManager.metricsSettings = metricsSettings;
RegistryFactory result = INSTANCE.get();
result.update(metricsSettings);
return result;
});
}

static synchronized RegistryFactory getInstance(ComponentMetricsSettings componentMetricsSettings) {
return componentMetricsSettings.isEnabled()
static RegistryFactory getInstance(ComponentMetricsSettings componentMetricsSettings) {

return accessMetricsSettings(() -> componentMetricsSettings.isEnabled()
? INSTANCE.get()
: NO_OP_INSTANCE;
: NO_OP_INSTANCE);
}

@Deprecated
static RegistryFactory getInstance(Config config) {
return getInstance(MetricsSettings.create(config));
}

private static <T> T accessMetricsSettings(Supplier<T> operation) {
SETTINGS_ACCESS.lock();
try {
return operation.get();
} finally {
SETTINGS_ACCESS.unlock();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates.
* Copyright (c) 2021, 2022 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 @@ -21,8 +21,9 @@
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand All @@ -32,10 +33,6 @@
* Some enrollments might arrive before the manager is started. We save those and act on them once the
* manager starts. This makes sure the executor's thread starts only at native image runtime.
* </p>
* <p>
* In production use, starting and stopping the executor and even enrolling callbacks are not performance-critical operations,
* so simple synchronization on methods which access shared data is clear and sufficient.
* </p>
*/
class PeriodicExecutor {

Expand Down Expand Up @@ -81,7 +78,7 @@ private static class Enrollment {

private final Collection<Enrollment> deferredEnrollments = new ArrayList<>();

private final Semaphore access = new Semaphore(1, true);
private final Lock access = new ReentrantLock(true);

private PeriodicExecutor() {
}
Expand Down Expand Up @@ -173,12 +170,11 @@ State executorState() {
}

private void sync(String taskDescription, Runnable task) {
access.lock();
try {
access.acquire();
task.run();
access.release();
} catch (InterruptedException ex) {
LOGGER.log(Level.WARNING, "Attempt to " + taskDescription + " failed", ex);
} finally {
access.unlock();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
package io.helidon.metrics;

import java.util.EnumMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import io.helidon.config.Config;
import io.helidon.metrics.api.MetricsSettings;
Expand Down Expand Up @@ -45,7 +46,7 @@
public class RegistryFactory implements io.helidon.metrics.api.RegistryFactory {

private final EnumMap<Type, Registry> registries = new EnumMap<>(Type.class);
private final Semaphore metricsSettingsAccess = new Semaphore(1);
private final Lock metricsSettingsAccess = new ReentrantLock(true);
private MetricsSettings metricsSettings;

/**
Expand All @@ -68,12 +69,11 @@ private RegistryFactory(MetricsSettings metricsSettings) {
}

private void accessMetricsSettings(Runnable operation) {
metricsSettingsAccess.lock();
try {
metricsSettingsAccess.acquire();
operation.run();
metricsSettingsAccess.release();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
metricsSettingsAccess.unlock();
}
}

Expand Down Expand Up @@ -164,7 +164,7 @@ public void update(MetricsSettings metricsSettings) {
});
}

private synchronized void ensureBase() {
private void ensureBase() {
tjquinno marked this conversation as resolved.
Show resolved Hide resolved
if (null == registries.get(Type.BASE)) {
accessMetricsSettings(() -> {
Registry registry = BaseRegistry.create(metricsSettings);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020 Oracle and/or its affiliates.
* Copyright (c) 2019, 2022 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 @@ -15,6 +15,10 @@
*/
package io.helidon.microprofile.cdi;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;

import io.helidon.common.LogConfig;

/**
Expand All @@ -25,6 +29,8 @@
final class BuildTimeInitializer {
private static volatile HelidonContainerImpl container;

private static final Lock CONTAINER_ACCESS = new ReentrantLock(true);

static {
// need to initialize logging as soon as possible
LogConfig.initClass();
Expand All @@ -34,21 +40,38 @@ final class BuildTimeInitializer {
private BuildTimeInitializer() {
}

static synchronized HelidonContainerImpl get() {
if (null == container) {
createContainer();
}
static HelidonContainerImpl get() {
return accessContainer(() -> {
if (null == container) {
createContainer();
}

return container;
return container;
});
}

static synchronized void reset() {
container = null;
static void reset() {
accessContainer(() -> {
container = null;
return null;
});
}

private static void createContainer() {
// static initialization to support GraalVM native image
container = HelidonContainerImpl.create();
ContainerInstanceHolder.addListener(BuildTimeInitializer::reset);
accessContainer(() -> {
container = HelidonContainerImpl.create();
ContainerInstanceHolder.addListener(BuildTimeInitializer::reset);
return null;
});
}

private static <T> T accessContainer(Supplier<T> operation) {
CONTAINER_ACCESS.lock();
try {
return operation.get();
} finally {
CONTAINER_ACCESS.unlock();
}
}
}
Loading