diff options
Diffstat (limited to 'server/sonar-process/src/main/java/org/sonar/process')
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 |