db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mi...@apache.org
Subject svn commit: r356884 - /db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/RAFContainer.java
Date Wed, 14 Dec 2005 21:40:50 GMT
Author: mikem
Date: Wed Dec 14 13:40:44 2005
New Revision: 356884

URL: http://svn.apache.org/viewcvs?rev=356884&view=rev
Log:
Fix for DERBY-733.  Committed on behalf of Knut Anders Hatlen.

I have attached a patch which invokes ReentrantLock.lock() and
unlock() when reading in a page from disk. I did not build my own
ReentrantLock replacement, as I said I would. Instead, I have used
reflection to enable this feature if the JVM supports it. This seemed
like an easier approach, and I also discovered that the handling of
threads waiting for monitors had changed between 1.4 and 1.5 and that
this issue was not so serious on 1.4.

The maximum response time was drastically reduced in the disk-bound
case. Derbyall ran successfully on both Sun JVM 1.4.2 and 1.5.0. I
have also tested the performance, and I could not see any change in
throughput or CPU usage. (The performance test was run with a very
small page cache and with a database that was many times bigger than
the page cache, but smaller than the file system cache. This way,
Derby called readPage() very often, but it was CPU-bound since the
requested page always was in the file system cache.) 


Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/RAFContainer.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/RAFContainer.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/RAFContainer.java?rev=356884&r1=356883&r2=356884&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/RAFContainer.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/RAFContainer.java
Wed Dec 14 13:40:44 2005
@@ -54,6 +54,8 @@
 import java.security.AccessController;
 import java.security.PrivilegedExceptionAction;
 import java.security.PrivilegedActionException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Constructor;
 
 /**
 	RAFContainer (short for RandomAccessFileContainer) is a concrete subclass of FileContainer
@@ -93,6 +95,43 @@
 	private boolean inBackup = false;
 	private boolean inRemove = false;
 
+	/* Fields with references to classes and methods in ReentrantLock
+	 * introduced in Java 1.5. Reflection is used to only use these
+     * interfaces if they exist.
+     * 
+     */
+	private static Class fairLockClass;
+	private static Constructor fairLockConstructor;
+	private static Method lock;
+	private static Method unlock;
+	private static boolean hasJava5FairLocks = false;
+
+	// Use reflection to find the constructor, lock() and unlock() in
+	// java.util.concurrent.locks.ReentrantLock. If the class and its
+	// methods are found, hasJava5FairLocks will be true and fair
+	// locking can be used.
+	static {
+		try {
+			fairLockClass = 
+                Class.forName("java.util.concurrent.locks.ReentrantLock");
+
+			fairLockConstructor = 
+                fairLockClass.getConstructor(new Class[] { Boolean.TYPE });
+
+			lock   = fairLockClass.getMethod("lock",   new Class[0]);
+			unlock = fairLockClass.getMethod("unlock", new Class[0]);
+			hasJava5FairLocks = true;
+		}
+		catch (NoSuchMethodException nsme) {}
+		catch (ClassNotFoundException cnfe) {}
+	}
+
+	/**
+	 * Object of type java.util.concurrent.locks.ReentrantLock. It is
+	 * used to prevent starvation when many threads are reading from
+	 * the same file.
+	 */
+	private Object fairLock;
 
 	/*
 	 * Constructors
@@ -100,6 +139,21 @@
 
 	RAFContainer(BaseDataFileFactory factory) {
 		super(factory);
+
+		// If Java 1.5 fair locks are available, construct one.
+		if (hasJava5FairLocks) {
+			try {
+				// construct a lock with fairness set to true
+				fairLock = 
+                    fairLockConstructor.newInstance(
+                        new Object[] { Boolean.TRUE });
+			} catch (Exception e) {
+				if (SanityManager.DEBUG) {
+					SanityManager.THROWASSERT(
+                        "failed constructing ReentrantLock", e);
+				}
+			}
+		}
 	}
 
 	/*
@@ -227,11 +281,39 @@
 
 		long pageOffset = pageNumber * pageSize;
 
-		synchronized (this) {
-
-			fileData.seek(pageOffset);
+		// Use Java 1.5 fair locks if they are available.
+		if (hasJava5FairLocks) {
+			try {
+				lock.invoke(fairLock, null);
+			} catch (Exception e) {
+				if (SanityManager.DEBUG) {
+					SanityManager.THROWASSERT(
+                        "failed invoking ReentrantLock.lock()", e);
+				}
+			}
+		}
 
-			fileData.readFully(pageData, 0, pageSize);
+		try {
+			// Starvation might occur at this point if many threads
+			// are waiting for the monitor. This section is therefore
+			// surrounded by calls to ReentrantLock.lock()/unlock() if
+			// we are running Java 1.5 or higher.
+			synchronized (this) {
+				fileData.seek(pageOffset);
+				fileData.readFully(pageData, 0, pageSize);
+			}
+		} finally {
+			// Unlock this section.
+			if (hasJava5FairLocks) {
+				try {
+					unlock.invoke(fairLock, null);
+				} catch (Exception e) {
+					if (SanityManager.DEBUG) {
+						SanityManager.THROWASSERT(
+                            "failed invoking ReentrantLock.unlock()", e);
+					}
+				}
+			}
 		}
 
 		if (dataFactory.databaseEncrypted() &&



Mime
View raw message