Skip to content

Commit

Permalink
Convert ConcurrentHashMap which does service loading to HashMap w…
Browse files Browse the repository at this point in the history
…ith `ReentrantLock` (helidon-io#8977)

* Convert ConcurrentHashMap which does service loading to HashMap with ReentrantLock

Signed-off-by: Tim Quinn <[email protected]>

* Use a RW lock

* Replace the contentious ConcurrentHashMap with a HashMap (with the lock) (which was the whole point after all)

---------

Signed-off-by: Tim Quinn <[email protected]>
  • Loading branch information
tjquinno authored and barchetta committed Jul 15, 2024
1 parent 0948faa commit 2acc767
Showing 1 changed file with 25 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
* Copyright (c) 2022, 2024 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 @@ -17,12 +17,15 @@
package io.helidon.common.configurable;

import java.lang.System.Logger.Level;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Supplier;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -50,7 +53,8 @@ class ObserverManager {
private static final LazyValue<List<ExecutorServiceSupplierObserver>> OBSERVERS = LazyValue
.create(ObserverManager::loadObservers);

private static final Map<Supplier<? extends ExecutorService>, SupplierInfo> SUPPLIERS = new ConcurrentHashMap<>();
private static final Map<Supplier<? extends ExecutorService>, SupplierInfo> SUPPLIERS = new HashMap<>();
private static final ReadWriteLock SUPPLIERS_LOCK = new ReentrantReadWriteLock();

// A given supplier category can have multiple suppliers, so keep track of the next available index by category.
private static final Map<String, AtomicInteger> SUPPLIER_CATEGORY_NEXT_INDEX_VALUES = new ConcurrentHashMap<>();
Expand All @@ -71,13 +75,18 @@ private ObserverManager() {
static void registerSupplier(Supplier<? extends ExecutorService> supplier,
String supplierCategory,
String executorServiceCategory) {
int supplierIndex = SUPPLIER_CATEGORY_NEXT_INDEX_VALUES.computeIfAbsent(supplierCategory, key -> new AtomicInteger())
.getAndIncrement();
SUPPLIERS.computeIfAbsent(supplier,
s -> SupplierInfo.create(s,
executorServiceCategory,
supplierCategory,
supplierIndex));
SUPPLIERS_LOCK.writeLock().lock();
try {
int supplierIndex = SUPPLIER_CATEGORY_NEXT_INDEX_VALUES.computeIfAbsent(supplierCategory, key -> new AtomicInteger())
.getAndIncrement();
SUPPLIERS.computeIfAbsent(supplier,
s -> SupplierInfo.create(s,
executorServiceCategory,
supplierCategory,
supplierIndex));
} finally {
SUPPLIERS_LOCK.writeLock().unlock();
}
}

/**
Expand All @@ -90,7 +99,13 @@ static void registerSupplier(Supplier<? extends ExecutorService> supplier,
* @throws IllegalStateException if the supplier has not previously registered itself
*/
static <E extends ExecutorService> E registerExecutorService(Supplier<E> supplier, E executorService) {
SupplierInfo supplierInfo = SUPPLIERS.get(supplier);
SUPPLIERS_LOCK.readLock().lock();
SupplierInfo supplierInfo;
try {
supplierInfo = SUPPLIERS.get(supplier);
} finally {
SUPPLIERS_LOCK.readLock().unlock();
}
if (supplierInfo == null) {
throw new IllegalStateException("Attempt to register an executor service to an unregistered supplier");
}
Expand Down

0 comments on commit 2acc767

Please sign in to comment.