aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-process/src/main/java/org/sonar/process
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-process/src/main/java/org/sonar/process')
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java5
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/cluster/hz/DistributedLock.java85
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/cluster/hz/DistributedReference.java69
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMember.java3
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMemberImpl.java9
5 files changed, 164 insertions, 7 deletions
diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java
index 3cf08d4085f..fd13abb2bfb 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java
@@ -101,7 +101,10 @@ public class ProcessProperties {
WEB_HTTP_MAX_THREADS("sonar.web.http.maxThreads"),
WEB_HTTP_ACCEPT_COUNT("sonar.web.http.acceptCount"),
WEB_HTTP_KEEP_ALIVE_TIMEOUT("sonar.web.http.keepAliveTimeout"),
- WEB_SESSION_TIMEOUT_IN_MIN("sonar.web.sessionTimeoutInMinutes"),
+ // The time a user can remain idle (no activity) before the session ends.
+ WEB_INACTIVE_SESSION_TIMEOUT_IN_MIN("sonar.web.sessionTimeoutInMinutes"),
+ // The time a user can remain logged in, regardless of activity
+ WEB_ACTIVE_SESSION_TIMEOUT_IN_MIN("sonar.web.activeSessionTimeoutInMinutes"),
WEB_SYSTEM_PASS_CODE("sonar.web.systemPasscode"),
WEB_ACCESSLOGS_ENABLE("sonar.web.accessLogs.enable"),
WEB_ACCESSLOGS_PATTERN("sonar.web.accessLogs.pattern"),
diff --git a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/DistributedLock.java b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/DistributedLock.java
new file mode 100644
index 00000000000..e0cb7c6dd65
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/DistributedLock.java
@@ -0,0 +1,85 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2025 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.cluster.hz;
+
+import com.hazelcast.map.IMap;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+
+public class DistributedLock implements Lock {
+ private final IMap<String, UUID> lockMap;
+ private final String lockName;
+ private final UUID ownerId;
+
+ public DistributedLock(IMap<String, UUID> lockMap, String lockName) {
+ this.lockMap = lockMap;
+ this.lockName = lockName;
+ // Unique ID for this lock owner
+ this.ownerId = UUID.randomUUID();
+ }
+
+ @Override
+ public void lock() {
+ while (!tryLock()) {
+ try {
+ // Retry after a short delay
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException("Thread interrupted while acquiring lock");
+ }
+ }
+ }
+
+ @Override
+ public void unlock() {
+ lockMap.computeIfPresent(lockName, (key, value) -> value.equals(ownerId) ? null : value);
+ }
+
+ @Override
+ public boolean tryLock() {
+ return lockMap.putIfAbsent(lockName, ownerId) == null;
+ }
+
+ @Override
+ public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
+ long deadline = System.currentTimeMillis() + unit.toMillis(time);
+ while (System.currentTimeMillis() < deadline) {
+ if (tryLock()) {
+ return true;
+ }
+ // Retry after a short delay
+ Thread.sleep(10);
+ }
+ return false;
+ }
+
+ @Override
+ public Condition newCondition() {
+ throw new UnsupportedOperationException("Conditions are not supported in DistributedLock");
+ }
+
+ @Override
+ public void lockInterruptibly() throws InterruptedException {
+ throw new UnsupportedOperationException("Interruptible locking is not supported in DistributedLock");
+ }
+}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/DistributedReference.java b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/DistributedReference.java
new file mode 100644
index 00000000000..e21d7846eff
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/DistributedReference.java
@@ -0,0 +1,69 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2025 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.cluster.hz;
+
+import com.hazelcast.map.IMap;
+import javax.annotation.Nullable;
+
+public class DistributedReference<E> {
+ private static final String ATOMIC_KEY = "atomicKey";
+
+ private final IMap<String, E> lockMap;
+
+ public DistributedReference(IMap<String, E> lockMap) {
+ this.lockMap = lockMap;
+ }
+
+ public E get() {
+ return lockMap.get(ATOMIC_KEY);
+ }
+
+ public void set(@Nullable E value) {
+ lockMap.lock(ATOMIC_KEY);
+ try {
+ putOrRemove(value);
+ } finally {
+ lockMap.unlock(ATOMIC_KEY);
+ }
+ }
+
+ public boolean compareAndSet(@Nullable E expected, @Nullable E newValue) {
+ lockMap.lock(ATOMIC_KEY);
+ try {
+ if ((expected == null && lockMap.get(ATOMIC_KEY) == null) ||
+ (expected != null && expected.equals(lockMap.get(ATOMIC_KEY)))) {
+ putOrRemove(newValue);
+ return true;
+ }
+ return false;
+ } finally {
+ lockMap.unlock(ATOMIC_KEY);
+ }
+ }
+
+ private void putOrRemove(@org.jetbrains.annotations.Nullable E value) {
+ if (value != null) {
+ lockMap.put(ATOMIC_KEY, value);
+ } else {
+ lockMap.remove(ATOMIC_KEY);
+ }
+ }
+
+}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMember.java b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMember.java
index f46bda5f8c1..03a0442d5a7 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMember.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMember.java
@@ -21,7 +21,6 @@ package org.sonar.process.cluster.hz;
import com.hazelcast.cluster.Cluster;
import com.hazelcast.cluster.MemberSelector;
-import com.hazelcast.cp.IAtomicReference;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -51,7 +50,7 @@ public interface HazelcastMember extends AutoCloseable {
}
}
- <E> IAtomicReference<E> getAtomicReference(String name);
+ <E> DistributedReference<E> getAtomicReference(String name);
/**
* Gets the replicated map shared by the cluster and identified by name.
diff --git a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMemberImpl.java b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMemberImpl.java
index 7dcda62e7fb..6fce2b1eadd 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMemberImpl.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMemberImpl.java
@@ -26,7 +26,7 @@ import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.HazelcastInstanceNotActiveException;
import com.hazelcast.core.IExecutorService;
import com.hazelcast.core.MultiExecutionCallback;
-import com.hazelcast.cp.IAtomicReference;
+import com.hazelcast.map.IMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -47,8 +47,8 @@ class HazelcastMemberImpl implements HazelcastMember {
}
@Override
- public <E> IAtomicReference<E> getAtomicReference(String name) {
- return hzInstance.getCPSubsystem().getAtomicReference(name);
+ public <E> DistributedReference<E> getAtomicReference(String name) {
+ return new DistributedReference<>(hzInstance.getMap(name));
}
@Override
@@ -68,7 +68,8 @@ class HazelcastMemberImpl implements HazelcastMember {
@Override
public Lock getLock(String s) {
- return hzInstance.getCPSubsystem().getLock(s);
+ IMap<String, UUID> lockMap = hzInstance.getMap("distributedLocks");
+ return new DistributedLock(lockMap, s);
}
@Override