Skip to content

Avoid global monitor on every bind in getDefaultPasswordPolicy#669

Open
vharseko wants to merge 1 commit into
OpenIdentityPlatform:masterfrom
vharseko:features/bind-4
Open

Avoid global monitor on every bind in getDefaultPasswordPolicy#669
vharseko wants to merge 1 commit into
OpenIdentityPlatform:masterfrom
vharseko:features/bind-4

Conversation

@vharseko

@vharseko vharseko commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary

Another BIND hot-path serialization point found while profiling after #660:
DirectoryServer.getDefaultPasswordPolicy() takes the global
authenticationPolicies monitor on every call just to read an
already-cached value — and the method is called for every authentication
(AuthenticationPolicy.forUser resolves the default policy for any user
without a per-user policy). This PR makes the cache read lock-free.

Problem

public static PasswordPolicy getDefaultPasswordPolicy()
{
  synchronized (directoryServer.authenticationPolicies)   // on every bind
  {
    ... return directoryServer.defaultPasswordPolicy;     // cached value
  }
}

JFR jdk.JavaMonitorEnter under concurrent BIND load shows worker threads
blocking on this monitor; contention grows as the other bind-path locks are
removed:

configuration profiled contention events total blocked (80 s window, 16 workers)
access loggers disabled (#668) 24 0.5 s
+ digestLock removed (#667) 96 2.0 s
this PR 0 0

Change

  • defaultPasswordPolicy becomes volatile; all mutations already happen
    under the authenticationPolicies monitor (register/deregister/reset),
    so the cache stays coherent.
  • getDefaultPasswordPolicy() returns the cached value lock-free and falls
    back to the existing synchronized slow path (unchanged, including its
    assertions) only when the cache is empty — at startup or right after a
    configuration change.

Benchmark / verification

Environment: packaged server built from this tree, je backend, 5,000
users (uid=user.N, {SSHA}) via setup --sampleData 5000, JDK 11,
8-core host, 2 GB heap, both access loggers disabled for comparability with
the #667/#668 profiles.

Load: authrate — 200 persistent connections re-binding as random users,
30 s warm-up:

authrate -h 127.0.0.1 -p 3389 -c 200 -f -B 30 -d 130 -i 5 \
  -D "uid=user.%d,ou=People,dc=example,dc=com" -w password \
  -g "rand(0,5000)"

Profiling: jcmd <pid> JFR.start settings=profile duration=80s during
steady state; jfr print --events jdk.JavaMonitorEnter aggregated by
monitor class + first application frame.

Result: zero JavaMonitorEnter events at getDefaultPasswordPolicy
(24–96 before, depending on how many other bind-path locks were already
removed). authrate errors: 0. Throughput at the 8-core saturation point
is unchanged within noise, as expected for a fix whose value is removing a
serialization ceiling on wider machines — same rationale as #667.

Testing

mvn -P precommit -pl opendj-server-legacy verify for
BindOperationTestCase (1140), PasswordPolicyTestCase (143),
SubentryPasswordPolicyTestCase (11): 1294 tests, 0 failures.

Files

  • opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java

getDefaultPasswordPolicy() took the authenticationPolicies monitor on
every call just to read an already-cached value, and the method is
called for every authentication. Under concurrent BIND load JFR shows
worker threads blocking on this monitor (96 contention events / ~2 s
blocked per 80 s window at 16 worker threads once other bind-path locks
are removed).

Make the defaultPasswordPolicy cache volatile and read it lock-free,
falling back to the existing synchronized slow path only when the cache
is empty (startup or configuration change). All mutations already
happen under the authenticationPolicies monitor.
@vharseko vharseko added the performance Performance / concurrency / lock-contention work label Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

benchmark enhancement performance Performance / concurrency / lock-contention work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants