From 099f991f4a13c13f9a1bd0750e27a49ff861a73c Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Thu, 04 Sep 2025 07:55:09 +0000
Subject: [PATCH] [#545] Add GroupManager writeLock performance (#551)
---
opendj-server-legacy/src/test/java/org/opends/server/core/GroupManagerTestCase.java | 54 +++++++++++++++++++++++++++
opendj-server-legacy/src/main/java/org/opends/server/core/GroupManager.java | 59 +++++++++++------------------
2 files changed, 77 insertions(+), 36 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/GroupManager.java b/opendj-server-legacy/src/main/java/org/opends/server/core/GroupManager.java
index fc1ca49..458a6ab 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/GroupManager.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/GroupManager.java
@@ -13,6 +13,7 @@
*
* Copyright 2007-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2025 3A Systems,LLC.
*/
package org.opends.server.core;
@@ -726,48 +727,34 @@
return;
}
+ Group<?> group =null;
lock.readLock().lock();
- try
- {
- if (!groupInstances.containsKey(oldEntry.getName()))
- {
- // If the modified entry is not in any group instance, it's probably
- // not a group, exit fast
- return;
- }
+ try{
+ group = groupInstances.get(oldEntry.getName());
}
finally
{
- lock.readLock().unlock();
+ lock.readLock().unlock();
}
-
- lock.writeLock().lock();
- try
- {
- Group<?> group = groupInstances.get(oldEntry.getName());
- if (group != null)
- {
- if (!oldEntry.getName().equals(newEntry.getName())
- || !group.mayAlterMemberList()
- || updatesObjectClass(modifications))
- {
- groupInstances.remove(oldEntry.getName());
- // This updates the refreshToken
- createAndRegisterGroup(newEntry);
+ if (group!=null) {
+ try {
+ if (!oldEntry.getName().equals(newEntry.getName())
+ || !group.mayAlterMemberList()
+ || updatesObjectClass(modifications)) {
+ lock.writeLock().lock();
+ try {
+ groupInstances.remove(oldEntry.getName());
+ // This updates the refreshToken
+ createAndRegisterGroup(newEntry);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ } else {
+ group.updateMembers(modifications);
+ }
+ } catch (UnsupportedOperationException | DirectoryException e) {
+ logger.traceException(e);
}
- else
- {
- group.updateMembers(modifications);
- }
- }
- }
- catch (UnsupportedOperationException | DirectoryException e)
- {
- logger.traceException(e);
- }
- finally
- {
- lock.writeLock().unlock();
}
}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/core/GroupManagerTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/core/GroupManagerTestCase.java
index 140f825..a4449fc 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/core/GroupManagerTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/core/GroupManagerTestCase.java
@@ -13,12 +13,17 @@
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2025 3A Systems, LLC
*/
package org.opends.server.core;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.ResultCode;
@@ -2292,6 +2297,55 @@
TestCaseUtils.clearBackend("userRoot");
}
+ @Test
+ public void test_issue_535() throws Exception {
+ TestCaseUtils.clearBackend("userRoot", "dc=example,dc=com");
+ TestCaseUtils.addEntries(
+ "dn: ou=Users,dc=example,dc=com",
+ "objectClass: organizationalUnit",
+ "objectClass: top",
+ "ou: Users",
+ "",
+ "dn: ou=Groups,dc=example,dc=com",
+ "objectClass: organizationalUnit",
+ "objectClass: top",
+ "ou: Groups",
+ "",
+ "dn: cn=Test User,ou=Users,dc=example,dc=com",
+ "objectClass: inetOrgPerson",
+ "objectClass: organizationalPerson",
+ "objectClass: person",
+ "objectClass: top",
+ "uid: testuser",
+ "cn: Test User",
+ "sn: User",
+ "userPassword: password123",
+ "",
+ "dn: cn=Level1,ou=Groups,dc=example,dc=com",
+ "objectClass: groupOfNames",
+ "objectClass: top",
+ "cn: Level1",
+ "member: cn=Test User,ou=Users,dc=example,dc=com",
+ "",
+ "dn: cn=Level2,ou=Groups,dc=example,dc=com",
+ "objectClass: groupOfNames",
+ "objectClass: top",
+ "cn: Level2",
+ "member: cn=Level1,ou=Groups,dc=example,dc=com",
+ ""
+ );
+ ExecutorService executor = Executors.newFixedThreadPool(100);
+ for (int i = 0; i < 10000; i++) {
+ executor.submit(() -> {
+ final ModifyRequest modifyRequest = newModifyRequest(DN.valueOf("cn=Level2,ou=Groups,dc=example,dc=com"));
+ modifyRequest.addModification(REPLACE, "member", "cn=Test User,ou=Users,dc=example,dc=com");
+ ModifyOperation modifyOperation = getRootConnection().processModify(modifyRequest);
+ assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+ });
+ }
+ executor.shutdown();
+ assertTrue(executor.awaitTermination(1, TimeUnit.MINUTES));
+ }
/**
* Adds nested group entries.
*
--
Gitblit v1.10.0