diff --git a/src/com/unboundid/ldap/listener/InMemoryRequestHandler.java b/src/com/unboundid/ldap/listener/InMemoryRequestHandler.java index c1cb7ca8e..954901d93 100644 --- a/src/com/unboundid/ldap/listener/InMemoryRequestHandler.java +++ b/src/com/unboundid/ldap/listener/InMemoryRequestHandler.java @@ -160,8 +160,15 @@ import com.unboundid.util.ThreadSafety; import com.unboundid.util.ThreadSafetyLevel; -import static com.unboundid.ldap.listener.ListenerMessages.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import static com.unboundid.ldap.listener.ListenerMessages.*; /** @@ -285,7 +292,9 @@ public final class InMemoryRequestHandler @NotNull private final Map entryMap; - + ReadWriteLock lock = new ReentrantReadWriteLock(); + Lock writeLock = lock.writeLock(); + Lock readLock = lock.readLock(); /** * Creates a new instance of this request handler with an initially-empty * data set. @@ -578,10 +587,13 @@ public InMemoryRequestHandler newInstance( @NotNull() public InMemoryDirectoryServerSnapshot createSnapshot() { - synchronized (entryMap) - { + try { + readLock.lock(); + return new InMemoryDirectoryServerSnapshot(entryMap, firstChangeNumber.get(), lastChangeNumber.get()); + } finally { + readLock.unlock(); } } @@ -597,8 +609,8 @@ public InMemoryDirectoryServerSnapshot createSnapshot() public void restoreSnapshot( @NotNull final InMemoryDirectoryServerSnapshot snapshot) { - synchronized (entryMap) - { + try { + writeLock.lock(); entryMap.clear(); entryMap.putAll(snapshot.getEntryMap()); @@ -621,6 +633,8 @@ public void restoreSnapshot( firstChangeNumber.set(snapshot.getFirstChangeNumber()); lastChangeNumber.set(snapshot.getLastChangeNumber()); + } finally { + writeLock.unlock(); } } @@ -890,8 +904,8 @@ public LDAPMessage processAddRequest(final int messageID, @NotNull final AddRequestProtocolOp request, @NotNull final List controls) { - synchronized (entryMap) - { + try { + writeLock.lock(); // Sleep before processing, if appropriate. sleepBeforeProcessing(); @@ -1288,6 +1302,8 @@ ResultCode.NO_SUCH_OBJECT_INT_VALUE, getMatchedDNString(dn), ResultCode.NO_SUCH_OBJECT_INT_VALUE, null, ERR_MEM_HANDLER_ADD_NOT_BELOW_BASE_DN.get(request.getDN()), null)); + } finally { + writeLock.unlock(); } } @@ -1367,8 +1383,8 @@ public LDAPMessage processBindRequest(final int messageID, @NotNull final BindRequestProtocolOp request, @NotNull final List controls) { - synchronized (entryMap) - { + try { + readLock.lock(); // Sleep before processing, if appropriate. sleepBeforeProcessing(); @@ -1584,6 +1600,8 @@ public LDAPMessage processBindRequest(final int messageID, new BindResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null, null), responseControls); + } finally { + readLock.unlock(); } } @@ -1616,8 +1634,8 @@ public LDAPMessage processCompareRequest(final int messageID, @NotNull final CompareRequestProtocolOp request, @NotNull final List controls) { - synchronized (entryMap) - { + try { + readLock.lock(); // Sleep before processing, if appropriate. sleepBeforeProcessing(); @@ -1742,6 +1760,8 @@ ResultCode.NO_SUCH_OBJECT_INT_VALUE, getMatchedDNString(dn), return new LDAPMessage(messageID, new CompareResponseProtocolOp(resultCode, null, null, null), responseControls); + } finally { + readLock.unlock(); } } @@ -1827,8 +1847,8 @@ public LDAPMessage processDeleteRequest(final int messageID, @NotNull final DeleteRequestProtocolOp request, @NotNull final List controls) { - synchronized (entryMap) - { + try { + writeLock.lock(); // Sleep before processing, if appropriate. sleepBeforeProcessing(); @@ -2025,6 +2045,8 @@ ResultCode.NO_SUCH_OBJECT_INT_VALUE, getMatchedDNString(dn), new DeleteResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null), responseControls); + } finally { + writeLock.unlock(); } } @@ -2101,8 +2123,8 @@ public LDAPMessage processExtendedRequest(final int messageID, @NotNull final ExtendedRequestProtocolOp request, @NotNull final List controls) { - synchronized (entryMap) - { + try { + writeLock.lock(); // Sleep before processing, if appropriate. sleepBeforeProcessing(); @@ -2181,6 +2203,8 @@ public LDAPMessage processExtendedRequest(final int messageID, StaticUtils.getExceptionMessage(e)), null, null, null)); } + } finally { + writeLock.unlock(); } } @@ -2268,8 +2292,8 @@ public LDAPMessage processModifyRequest(final int messageID, @NotNull final ModifyRequestProtocolOp request, @NotNull final List controls) { - synchronized (entryMap) - { + try { + writeLock.lock(); // Sleep before processing, if appropriate. sleepBeforeProcessing(); @@ -2561,6 +2585,8 @@ ResultCode.NO_SUCH_OBJECT_INT_VALUE, getMatchedDNString(dn), new ModifyResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null), responseControls); + } finally { + writeLock.unlock(); } } @@ -2954,8 +2980,8 @@ public LDAPMessage processModifyDNRequest(final int messageID, @NotNull final ModifyDNRequestProtocolOp request, @NotNull final List controls) { - synchronized (entryMap) - { + try { + writeLock.lock(); // Sleep before processing, if appropriate. sleepBeforeProcessing(); @@ -3393,6 +3419,8 @@ ResultCode.NO_SUCH_OBJECT_INT_VALUE, getMatchedDNString(newDN), new ModifyDNResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null), responseControls); + } finally { + writeLock.unlock(); } } @@ -3483,10 +3511,10 @@ private void handleReferentialIntegrityModifyDN(@NotNull final DN oldDN, @NotNull() public LDAPMessage processSearchRequest(final int messageID, @NotNull final SearchRequestProtocolOp request, - @NotNull final List controls) - { - synchronized (entryMap) - { + @NotNull final List controls) { + try { + readLock.lock(); + final List entryList = new ArrayList<>(entryMap.size()); final List referenceList = @@ -3514,25 +3542,26 @@ public LDAPMessage processSearchRequest(final int messageID, for (final SearchResultReference r : referenceList) { - try - { + connection.sendSearchResultReference(messageID, new SearchResultReferenceProtocolOp( StaticUtils.toList(r.getReferralURLs())), r.getControls()); - } - catch (final LDAPException le) - { - Debug.debugException(le); - return new LDAPMessage(messageID, - new SearchResultDoneProtocolOp(le.getResultCode().intValue(), - le.getMatchedDN(), le.getDiagnosticMessage(), - StaticUtils.toList(le.getReferralURLs())), - le.getResponseControls()); - } + } return returnMessage; + } catch (LDAPException e) { + Debug.debugException(e); + return new LDAPMessage(messageID, + new SearchResultDoneProtocolOp(e.getResultCode().intValue(), + e.getMatchedDN(), e.getDiagnosticMessage(), + StaticUtils.toList(e.getReferralURLs())), + e.getResponseControls()); + + + } finally { + readLock.unlock(); } } @@ -3576,10 +3605,13 @@ LDAPMessage processSearchRequest(final int messageID, @NotNull final SearchRequestProtocolOp request, @NotNull final List controls, @NotNull final List entryList, - @NotNull final List referenceList) - { - synchronized (entryMap) - { + @NotNull final List referenceList) throws LDAPSearchException { + boolean gotLock = false; + try{ + gotLock = readLock.tryLock(50,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } // Sleep before processing, if appropriate. final long processingStartTime = System.currentTimeMillis(); sleepBeforeProcessing(); @@ -3777,7 +3809,7 @@ else if (filterIncludesLDAPSubEntry(request.getFilter())) // attributes. final List fullEntryList = new ArrayList<>(entryMap.size()); -findEntriesAndRefs: + findEntriesAndRefs: { // Check the scope. If it is a base-level search, then we only need to // examine the base entry. Otherwise, we'll have to scan the entire @@ -4114,6 +4146,11 @@ else if (filterIncludesLDAPSubEntry(request.getFilter())) new SearchResultDoneProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null), responseControls); + } catch (LDAPException | InterruptedException e) { + throw new LDAPSearchException(ResultCode.TIMEOUT,"readlock"); + } finally { + if (gotLock) + readLock.unlock(); } } @@ -4591,8 +4628,8 @@ public List getPasswordsInEntry( */ public int countEntries(final boolean includeChangeLog) { - synchronized (entryMap) - { + try { + readLock.lock(); if (includeChangeLog || (maxChangelogEntries == 0)) { return entryMap.size(); @@ -4611,6 +4648,8 @@ public int countEntries(final boolean includeChangeLog) return count; } + } finally { + readLock.unlock(); } } @@ -4631,8 +4670,8 @@ public int countEntries(final boolean includeChangeLog) public int countEntriesBelow(@NotNull final String baseDN) throws LDAPException { - synchronized (entryMap) - { + try { + readLock.lock(); final DN parsedBaseDN = new DN(baseDN, schemaRef.get()); int count = 0; @@ -4645,6 +4684,8 @@ public int countEntriesBelow(@NotNull final String baseDN) } return count; + } finally { + readLock.unlock(); } } @@ -4657,10 +4698,9 @@ public int countEntriesBelow(@NotNull final String baseDN) */ public void clear() { - synchronized (entryMap) - { + restoreSnapshot(initialSnapshot); - } + } @@ -4686,8 +4726,8 @@ public int importFromLDIF(final boolean clear, @NotNull final LDIFReader ldifReader) throws LDAPException { - synchronized (entryMap) - { + try { + writeLock.lock(); final InMemoryDirectoryServerSnapshot snapshot = createSnapshot(); boolean restoreSnapshot = true; @@ -4747,6 +4787,8 @@ public int importFromLDIF(final boolean clear, restoreSnapshot(snapshot); } } + } finally { + writeLock.unlock(); } } @@ -4777,8 +4819,8 @@ public int exportToLDIF(@NotNull final LDIFWriter ldifWriter, final boolean closeWriter) throws LDAPException { - synchronized (entryMap) - { + try { + readLock.lock(); boolean exceptionThrown = false; try @@ -4849,7 +4891,9 @@ public int exportToLDIF(@NotNull final LDIFWriter ldifWriter, } } } - } + } finally { + readLock.unlock(); +} } @@ -4875,8 +4919,8 @@ public int exportToLDIF(@NotNull final LDIFWriter ldifWriter, public int applyChangesFromLDIF(@NotNull final LDIFReader ldifReader) throws LDAPException { - synchronized (entryMap) - { + try { + writeLock.lock(); final InMemoryDirectoryServerSnapshot snapshot = createSnapshot(); boolean restoreSnapshot = true; @@ -4962,7 +5006,9 @@ else if (changeRecord instanceof LDIFModifyDNChangeRecord) restoreSnapshot(snapshot); } } - } + } finally { + writeLock.unlock(); +} } @@ -5040,8 +5086,8 @@ public void addEntry(@NotNull final Entry entry, public void addEntries(@NotNull final List entries) throws LDAPException { - synchronized (entryMap) - { + try { + writeLock.lock(); final InMemoryDirectoryServerSnapshot snapshot = createSnapshot(); boolean restoreSnapshot = true; @@ -5060,6 +5106,8 @@ public void addEntries(@NotNull final List entries) restoreSnapshot(snapshot); } } + } finally { + writeLock.unlock(); } } @@ -5082,8 +5130,8 @@ public void addEntries(@NotNull final List entries) public int deleteSubtree(@NotNull final String baseDN) throws LDAPException { - synchronized (entryMap) - { + try { + writeLock.lock(); final DN dn = new DN(baseDN, schemaRef.get()); if (dn.isNullDN()) { @@ -5106,6 +5154,8 @@ public int deleteSubtree(@NotNull final String baseDN) } return numDeleted; + }finally { + writeLock.unlock(); } } @@ -5185,8 +5235,8 @@ public ReadOnlyEntry getEntry(@NotNull final String dn) @Nullable() public ReadOnlyEntry getEntry(@NotNull final DN dn) { - synchronized (entryMap) - { + try { + readLock.lock(); if (dn.isNullDN()) { return generateRootDSE(); @@ -5207,6 +5257,8 @@ else if (dn.equals(subschemaSubentryDN)) return new ReadOnlyEntry(e); } } + }finally { + readLock.unlock(); } } @@ -5234,8 +5286,12 @@ public List search(@NotNull final String baseDN, @NotNull final Filter filter) throws LDAPException { - synchronized (entryMap) - { + boolean gotLock = false; + try { + gotLock = readLock.tryLock(100,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final DN parsedDN; final Schema schema = schemaRef.get(); try @@ -5344,6 +5400,11 @@ else if (parsedDN.equals(subschemaSubentryDN)) } return Collections.unmodifiableList(entryList); + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + } finally { + if (gotLock) + readLock.unlock(); } } @@ -5958,8 +6019,8 @@ private DN handleProxiedAuthControl(@NotNull final Map m) public DN getDNForAuthzID(@NotNull final String authzID) throws LDAPException { - synchronized (entryMap) - { + try { + readLock.lock(); final String lowerAuthzID = StaticUtils.toLowerCase(authzID); if (lowerAuthzID.startsWith("dn:")) { @@ -6002,6 +6063,8 @@ else if (lowerAuthzID.startsWith("u:")) throw new LDAPException(ResultCode.AUTHORIZATION_DENIED, ERR_MEM_HANDLER_NO_SUCH_IDENTITY.get(authzID)); } + } finally { + readLock.unlock(); } } @@ -6256,8 +6319,12 @@ public boolean entryExists(@NotNull final String dn, @NotNull final String filter) throws LDAPException { - synchronized (entryMap) - { + boolean gotLock = false; + try { + gotLock = readLock.tryLock(100,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final Entry e = getEntry(dn); if (e == null) { @@ -6274,6 +6341,11 @@ public boolean entryExists(@NotNull final String dn, Debug.debugException(le); return false; } + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if (gotLock) + readLock.unlock(); } } @@ -6296,8 +6368,12 @@ public boolean entryExists(@NotNull final String dn, public boolean entryExists(@NotNull final Entry entry) throws LDAPException { - synchronized (entryMap) - { + boolean gotLock = false; + try { + gotLock = readLock.tryLock(100,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final Entry e = getEntry(entry.getDN()); if (e == null) { @@ -6316,6 +6392,11 @@ public boolean entryExists(@NotNull final Entry entry) } return true; + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if (gotLock) + readLock.unlock(); } } @@ -6359,8 +6440,12 @@ public void assertEntryExists(@NotNull final String dn, @NotNull final String filter) throws LDAPException, AssertionError { - synchronized (entryMap) - { + boolean gotLock = false; + try{ + gotLock = readLock.tryLock(50,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final Entry e = getEntry(dn); if (e == null) { @@ -6383,6 +6468,11 @@ public void assertEntryExists(@NotNull final String dn, throw new AssertionError( ERR_MEM_HANDLER_TEST_ENTRY_DOES_NOT_MATCH_FILTER.get(dn, filter)); } + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if (gotLock) + readLock.unlock(); } } @@ -6405,8 +6495,12 @@ public void assertEntryExists(@NotNull final String dn, public void assertEntryExists(@NotNull final Entry entry) throws LDAPException, AssertionError { - synchronized (entryMap) - { + boolean gotLock = false; + try{ + gotLock = readLock.tryLock(50,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final Entry e = getEntry(entry.getDN()); if (e == null) { @@ -6445,6 +6539,11 @@ public void assertEntryExists(@NotNull final Entry entry) { throw new AssertionError(StaticUtils.concatenateStrings(messages)); } + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if (gotLock) + readLock.unlock(); } } @@ -6466,8 +6565,12 @@ public void assertEntryExists(@NotNull final Entry entry) public List getMissingEntryDNs(@NotNull final Collection dns) throws LDAPException { - synchronized (entryMap) - { + boolean gotLock = false; + try{ + gotLock = readLock.tryLock(50,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final List missingDNs = new ArrayList<>(dns.size()); for (final String dn : dns) { @@ -6479,6 +6582,11 @@ public List getMissingEntryDNs(@NotNull final Collection dns) } return missingDNs; + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if (gotLock) + readLock.unlock(); } } @@ -6498,8 +6606,12 @@ public List getMissingEntryDNs(@NotNull final Collection dns) public void assertEntriesExist(@NotNull final Collection dns) throws LDAPException, AssertionError { - synchronized (entryMap) - { + boolean gotLock = false; + try{ + gotLock = readLock.tryLock(50,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final List missingDNs = getMissingEntryDNs(dns); if (missingDNs.isEmpty()) { @@ -6513,6 +6625,11 @@ public void assertEntriesExist(@NotNull final Collection dns) } throw new AssertionError(StaticUtils.concatenateStrings(messages)); + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if (gotLock) + readLock.unlock(); } } @@ -6539,8 +6656,12 @@ public List getMissingAttributeNames(@NotNull final String dn, @NotNull final Collection attributeNames) throws LDAPException { - synchronized (entryMap) - { + boolean gotLock = false; + try{ + gotLock = readLock.tryLock(50,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final Entry e = getEntry(dn); if (e == null) { @@ -6560,6 +6681,11 @@ public List getMissingAttributeNames(@NotNull final String dn, } return missingAttrs; + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if(gotLock) + readLock.unlock(); } } @@ -6583,8 +6709,12 @@ public void assertAttributeExists(@NotNull final String dn, @NotNull final Collection attributeNames) throws LDAPException, AssertionError { - synchronized (entryMap) - { + boolean gotLock = false; + try{ + gotLock = readLock.tryLock(50,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final List missingAttrs = getMissingAttributeNames(dn, attributeNames); if (missingAttrs == null) @@ -6603,6 +6733,11 @@ else if (missingAttrs.isEmpty()) } throw new AssertionError(StaticUtils.concatenateStrings(messages)); + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if (gotLock) + readLock.unlock(); } } @@ -6632,8 +6767,12 @@ public List getMissingAttributeValues(@NotNull final String dn, @NotNull final Collection attributeValues) throws LDAPException { - synchronized (entryMap) - { + boolean gotLock = false; + try{ + gotLock = readLock.tryLock(50,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final Entry e = getEntry(dn); if (e == null) { @@ -6653,6 +6792,11 @@ public List getMissingAttributeValues(@NotNull final String dn, } return missingValues; + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if (gotLock) + readLock.unlock(); } } @@ -6680,8 +6824,13 @@ public void assertValueExists(@NotNull final String dn, @NotNull final Collection attributeValues) throws LDAPException, AssertionError { - synchronized (entryMap) - { + boolean gotLock = false; + try{ + + gotLock = readLock.tryLock(50,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final List missingValues = getMissingAttributeValues(dn, attributeName, attributeValues); if (missingValues == null) @@ -6710,6 +6859,11 @@ else if (missingValues.isEmpty()) } throw new AssertionError(StaticUtils.concatenateStrings(messages)); + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if (gotLock) + readLock.unlock(); } } @@ -6755,8 +6909,12 @@ public void assertAttributeMissing(@NotNull final String dn, @NotNull final Collection attributeNames) throws LDAPException, AssertionError { - synchronized (entryMap) - { + boolean gotLock = false; + try{ + gotLock = readLock.tryLock(50,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final Entry e = getEntry(dn); if (e == null) { @@ -6778,6 +6936,11 @@ public void assertAttributeMissing(@NotNull final String dn, { throw new AssertionError(StaticUtils.concatenateStrings(messages)); } + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if (gotLock) + readLock.lock(); } } @@ -6803,8 +6966,12 @@ public void assertValueMissing(@NotNull final String dn, @NotNull final Collection attributeValues) throws LDAPException, AssertionError { - synchronized (entryMap) - { + boolean gotLock = false; + try{ + gotLock = readLock.tryLock(50,TimeUnit.MILLISECONDS); + if (!gotLock){ + throw new LDAPException(ResultCode.TIMEOUT,"readLock"); + } final Entry e = getEntry(dn); if (e == null) { @@ -6827,6 +6994,11 @@ public void assertValueMissing(@NotNull final String dn, { throw new AssertionError(StaticUtils.concatenateStrings(messages)); } + } catch (InterruptedException e) { + throw new LDAPException(ResultCode.TIMEOUT,e); + }finally { + if (gotLock) + readLock.unlock(); } } }