Skip to content

Commit 600ba64

Browse files
tulinkryVladimir Kotal
authored andcommitted
more efficient locking for shared resource with more readers than writers (#1565)
1 parent 58b8c11 commit 600ba64

File tree

1 file changed

+40
-13
lines changed

1 file changed

+40
-13
lines changed

src/org/opensolaris/opengrok/authorization/AuthorizationFramework.java

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import java.util.List;
3434
import java.util.Map;
3535
import java.util.TreeMap;
36+
import java.util.concurrent.locks.ReadWriteLock;
37+
import java.util.concurrent.locks.ReentrantReadWriteLock;
3638
import java.util.function.Predicate;
3739
import java.util.jar.JarEntry;
3840
import java.util.jar.JarFile;
@@ -73,6 +75,11 @@ public final class AuthorizationFramework {
7375
*/
7476
AuthorizationStack stack;
7577

78+
/**
79+
* Lock for safe reloads.
80+
*/
81+
private ReadWriteLock lock = new ReentrantReadWriteLock();
82+
7683
/**
7784
* Keeping track of the number of reloads in this framework. This can be
7885
* used by the plugins to invalidate the session and force reload the
@@ -205,17 +212,27 @@ protected String getClassName(IAuthorizationPlugin plugin) {
205212
*
206213
* @return the stack containing plugins/other stacks
207214
*/
208-
public synchronized AuthorizationStack getStack() {
209-
return stack;
215+
public AuthorizationStack getStack() {
216+
lock.readLock().lock();
217+
try {
218+
return stack;
219+
} finally {
220+
lock.readLock().unlock();
221+
}
210222
}
211223

212224
/**
213225
* Set the internal stack to this new value.
214226
*
215227
* @param s new stack to be used
216228
*/
217-
public synchronized void setStack(AuthorizationStack s) {
218-
this.stack = s;
229+
public void setStack(AuthorizationStack s) {
230+
lock.writeLock().lock();
231+
try {
232+
this.stack = s;
233+
} finally {
234+
lock.writeLock().unlock();
235+
}
219236
}
220237

221238
/**
@@ -495,16 +512,20 @@ public Object run() {
495512
// fire load events
496513
loadAllPlugins(newStack);
497514

515+
AuthorizationStack oldStack;
498516
/**
499-
* Replace the stack in a synchronized block to avoid inconsistent state
500-
* between the stack change and currently executing requests performing
501-
* some authorization on the same stack.
517+
* Replace the stack in a write lock to avoid inconsistent state between
518+
* the stack change and currently executing requests performing some
519+
* authorization on the same stack.
502520
*
503-
* @see #performCheck is also marked as synchronized
521+
* @see #performCheck is controlled with a read lock
504522
*/
505-
AuthorizationStack oldStack = stack;
506-
synchronized (this) {
523+
lock.writeLock().lock();
524+
try {
525+
oldStack = stack;
507526
stack = newStack;
527+
} finally {
528+
lock.writeLock().unlock();
508529
}
509530

510531
// clean the old stack
@@ -546,7 +567,8 @@ public void setPluginVersion(int pluginVersion) {
546567
}
547568

548569
/**
549-
* Checks if the request should have an access to a resource.
570+
* Checks if the request should have an access to a resource. This method is
571+
* thread safe with respect to the concurrent reload of plugins.
550572
*
551573
* <p>
552574
* Internally performed with a predicate. Using cache in request
@@ -645,7 +667,12 @@ private boolean checkAll(HttpServletRequest request, String cache, Nameable enti
645667
* successful for the given plugin
646668
* @return true if entity is allowed; false otherwise
647669
*/
648-
private synchronized boolean performCheck(Nameable entity, Predicate<IAuthorizationPlugin> predicate) {
649-
return stack.isAllowed(entity, predicate);
670+
private boolean performCheck(Nameable entity, Predicate<IAuthorizationPlugin> predicate) {
671+
lock.readLock().lock();
672+
try {
673+
return stack.isAllowed(entity, predicate);
674+
} finally {
675+
lock.readLock().unlock();
676+
}
650677
}
651678
}

0 commit comments

Comments
 (0)