From 4698e4fa18f652019b8f06fef1b2b8813446f5e0 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Wed, 03 Jan 2007 16:12:10 +0000
Subject: [PATCH] Update the task backend to properly acquire read locks on task and recurring task entries when evaluating them during search operations, and to acquire write locks for the entries when they are being updated. This should eliminate the possibility of concurrent modification exceptions being thrown in cases where a client issues a search for a task entry at the same time the task entry is being updated within the server.
---
opends/src/server/org/opends/server/backends/task/TaskScheduler.java | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 109 insertions(+), 10 deletions(-)
diff --git a/opends/src/server/org/opends/server/backends/task/TaskScheduler.java b/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
index 9472b79..491850b 100644
--- a/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
+++ b/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
@@ -37,6 +37,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;
+import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.opends.server.api.AlertGenerator;
@@ -55,6 +56,7 @@
import org.opends.server.types.InitializationException;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.LDIFExportConfig;
+import org.opends.server.types.LockManager;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import org.opends.server.util.LDIFException;
@@ -1448,7 +1450,83 @@
/**
- * Retrieves the scheduled task entry with the provided DN.
+ * Attempts to acquire a write lock on the specified entry, trying as many
+ * times as necessary until the lock has been acquired.
+ *
+ * @param entryDN The DN of the entry for which to acquire the write lock.
+ *
+ * @return The write lock that has been acquired for the entry.
+ */
+ Lock writeLockEntry(DN entryDN)
+ {
+ assert debugEnter(CLASS_NAME, "lockEntry", String.valueOf(entryDN));
+
+ Lock lock = LockManager.lockWrite(entryDN);
+ while (lock == null)
+ {
+ lock = LockManager.lockWrite(entryDN);
+ }
+
+ return lock;
+ }
+
+
+
+ /**
+ * Attempts to acquire a read lock on the specified entry, trying up to five
+ * times before failing.
+ *
+ * @param entryDN The DN of the entry for which to acquire the read lock.
+ *
+ * @return The read lock that has been acquired for the entry.
+ *
+ * @throws DirectoryException If the read lock cannot be acquired.
+ */
+ Lock readLockEntry(DN entryDN)
+ throws DirectoryException
+ {
+ assert debugEnter(CLASS_NAME, "lockEntry", String.valueOf(entryDN));
+
+ Lock lock = LockManager.lockRead(entryDN);
+ for (int i=0; ((lock == null) && (i < 4)); i++)
+ {
+ lock = LockManager.lockRead(entryDN);
+ }
+
+ if (lock == null)
+ {
+ int msgID = MSGID_BACKEND_CANNOT_LOCK_ENTRY;
+ String message = getMessage(msgID, String.valueOf(entryDN));
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+ message, msgID);
+ }
+ else
+ {
+ return lock;
+ }
+ }
+
+
+
+ /**
+ * Releases the lock held on the specified entry.
+ *
+ * @param entryDN The DN of the entry for which the lock is held.
+ * @param lock The lock held on the entry.
+ */
+ void unlockEntry(DN entryDN, Lock lock)
+ {
+ assert debugEnter(CLASS_NAME, "unlockEntry", String.valueOf(entryDN),
+ String.valueOf(lock));
+
+ LockManager.unlock(entryDN, lock);
+ }
+
+
+
+ /**
+ * Retrieves the scheduled task entry with the provided DN. The caller should
+ * hold a read lock on the target entry.
*
* @param scheduledTaskEntryDN The entry DN that indicates which scheduled
* task entry to retrieve.
@@ -1516,14 +1594,24 @@
{
for (Task t : tasks.values())
{
- Entry e = t.getTaskEntry();
- if (filter.matchesEntry(e))
+ DN taskEntryDN = t.getTaskEntryDN();
+ Lock lock = readLockEntry(taskEntryDN);
+
+ try
{
- if (! searchOperation.returnEntry(e, null))
+ Entry e = t.getTaskEntry();
+ if (filter.matchesEntry(e))
{
- return false;
+ if (! searchOperation.returnEntry(e, null))
+ {
+ return false;
+ }
}
}
+ finally
+ {
+ unlockEntry(taskEntryDN, lock);
+ }
}
return true;
@@ -1601,7 +1689,8 @@
/**
- * Retrieves the recurring task entry with the provided DN.
+ * Retrieves the recurring task entry with the provided DN. The caller should
+ * hold a read lock on the target entry.
*
* @param recurringTaskEntryDN The entry DN that indicates which recurring
* task entry to retrieve.
@@ -1669,14 +1758,24 @@
{
for (RecurringTask rt : recurringTasks.values())
{
- Entry e = rt.getRecurringTaskEntry();
- if (filter.matchesEntry(e))
+ DN recurringTaskEntryDN = rt.getRecurringTaskEntryDN();
+ Lock lock = readLockEntry(recurringTaskEntryDN);
+
+ try
{
- if (! searchOperation.returnEntry(e, null))
+ Entry e = rt.getRecurringTaskEntry();
+ if (filter.matchesEntry(e))
{
- return false;
+ if (! searchOperation.returnEntry(e, null))
+ {
+ return false;
+ }
}
}
+ finally
+ {
+ unlockEntry(recurringTaskEntryDN, lock);
+ }
}
return true;
--
Gitblit v1.10.0