Author: j16sdiz
Date: 2008-06-02 13:58:19 +0000 (Mon, 02 Jun 2008)
New Revision: 20181
Modified:
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java
Log:
use java.util.concurrent.locks.*
Modified:
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java
===================================================================
---
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java
2008-06-02 13:57:55 UTC (rev 20180)
+++
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java
2008-06-02 13:58:19 UTC (rev 20181)
@@ -15,6 +15,12 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import freenet.crypt.BlockCipher;
import freenet.crypt.PCFBMode;
@@ -107,6 +113,8 @@
if (logMINOR)
Logger.minor(this, "Fetch " +
HexUtil.bytesToHex(routingKey) + " for " + callback);
+ configLock.readLock().lock();
+ try {
Entry entry = probeEntry(routingKey);
if (entry == null) {
@@ -127,6 +135,9 @@
incMisses();
return null;
}
+ } finally {
+ configLock.readLock().unlock();
+ }
}
/**
@@ -185,6 +196,8 @@
if (logMINOR)
Logger.minor(this, "Putting " +
HexUtil.bytesToHex(routingKey) + " for " + callback);
+ configLock.readLock().lock();
+ try {
// don't use fetch(), as fetch() would do a miss++/hit++
Entry oldEntry = probeEntry(routingKey);
if (oldEntry != null) {
@@ -256,6 +269,9 @@
} finally {
unlockEntry(offset[0]);
}
+ } finally {
+ configLock.readLock().unlock();
+ }
}
// ------------- Entry I/O
@@ -757,6 +773,8 @@
* Write config file
*/
private void writeConfigFile() throws IOException {
+ configLock.writeLock().lock();
+ try {
File tempConfig = new File(configFile.getPath() + ".tmp");
RandomAccessFile raf = new RandomAccessFile(tempConfig, "rw");
raf.seek(0);
@@ -770,6 +788,9 @@
raf.close();
FileUtil.renameTo(tempConfig, configFile);
+ } finally {
+ configLock.writeLock().unlock();
+ }
}
// ------------- Store resizing
@@ -789,11 +810,17 @@
setDaemon(true);
}
+ @Override
public void run() {
while (!shutdown) {
synchronized (cleanerLock) {
+ configLock.readLock().lock();
+ try {
if (prevStoreSize != 0)
resizeStore();
+ } finally {
+ configLock.readLock().unlock();
+ }
cleanerLock.notifyAll();
try {
@@ -1094,19 +1121,6 @@
bf.flip();
return new Entry(bf);
}
-
- /**
- * Samples to take on key count estimation
- */
- private static final double SAMPLE_RATE = 0.05; // 5%
- /**
- * Minimum samples to take on key count estimation
- */
- private static final int MIN_SAMPLE = 10000;
- /**
- * Last sample position
- */
- private long samplePos = 0;
}
public void setMaxKeys(long newStoreSize, boolean shrinkNow) throws
IOException {
@@ -1115,7 +1129,8 @@
assert newStoreSize > 0;
// TODO assert newStoreSize > (141 * (3 * 3) + 13 * 3) * 2; //
store size too small
- synchronized (cleanerLock) {
+ configLock.writeLock().lock();
+ try {
if (newStoreSize == this.storeSize)
return;
@@ -1131,49 +1146,56 @@
prevStoreSize = storeSize;
storeSize = newStoreSize;
writeConfigFile();
+ synchronized (cleanerLock) {
cleanerLock.notifyAll();
+ }
if (shrinkNow) {
// TODO shrink now
}
+ } finally {
+ configLock.writeLock().unlock();
}
}
public void setBloomSync(boolean sync) {
- if (lockGlobal(Integer.MAX_VALUE)) {
+ configLock.writeLock().lock();
this.syncBloom = sync;
- unlockGlobal();
- }
+ configLock.writeLock().unlock();
}
// ------------- Locking
private boolean shutdown = false;
- private boolean lockedGlobal = false;
- private int lockingGlobal = 0;
- private Map lockMap = new HashMap();
+ private ReadWriteLock configLock = new ReentrantReadWriteLock();
+ private Lock entryLock = new ReentrantLock();
+ private Map<Long, Condition> lockMap = new HashMap<Long, Condition> ();
/**
* Lock the entry
*
- * This lock is <strong>not</strong> reentrance. No threads except
Cleaner should hold more then
- * one lock at a time (or deadlock may occur).
+ * This lock is <strong>not</strong> re-entrance. No threads except
Cleaner should hold more
+ * then one lock at a time (or deadlock may occur).
*/
private boolean lockEntry(long offset) {
if (logDEBUG && logLOCK)
Logger.debug(this, "try locking " + offset, new
Exception());
- Long lxr = new Long(offset);
-
try {
- synchronized (lockMap) {
- while (lockMap.containsKey(lxr) || lockedGlobal
|| lockingGlobal != 0) { // while someone hold the lock
+ entryLock.lock();
+ try {
+ do {
if (shutdown)
return false;
- lockMap.wait();
- }
-
- lockMap.put(lxr, Thread.currentThread());
+ Condition lockCond =
lockMap.get(offset);
+ if (lockCond != null)
+ lockCond.await(10,
TimeUnit.SECONDS); // 10s for checking shutdown
+ else
+ break;
+ } while (true);
+ lockMap.put(offset, entryLock.newCondition());
+ } finally {
+ entryLock.unlock();
}
} catch (InterruptedException e) {
Logger.error(this, "lock interrupted", e);
@@ -1191,57 +1213,16 @@
private void unlockEntry(long offset) {
if (logDEBUG && logLOCK)
Logger.debug(this, "unlocking " + offset);
- Long lxr = new Long(offset);
- synchronized (lockMap) {
- Object o = lockMap.remove(lxr);
- assert o == Thread.currentThread();
-
- lockMap.notifyAll();
- }
- }
-
- /**
- * Lock all entries.
- *
- * Use this method to stop all read / write before database shutdown.
- *
- * @param timeout
- * the maximum time to wait in milliseconds.
- */
- private boolean lockGlobal(long timeout) {
- synchronized (lockMap) {
+ entryLock.lock();
try {
- long startTime = System.currentTimeMillis();
- lockingGlobal++;
-
- while (!lockMap.isEmpty() || lockedGlobal) {
- lockMap.wait(timeout);
-
- if (System.currentTimeMillis() -
startTime > timeout)
- return false;
- }
-
- lockedGlobal = true;
- return true;
- } catch (InterruptedException e) {
- return false;
+ Condition cond = lockMap.remove(offset);
+ cond.signal();
} finally {
- lockingGlobal--;
- }
+ entryLock.unlock();
}
}
- /**
- * Unlock the global lock
- */
- private void unlockGlobal() {
- synchronized (lockMap) {
- lockedGlobal = false;
- lockMap.notifyAll();
- }
- }
-
public class ShutdownDB implements Runnable {
public void run() {
shutdown = true;
@@ -1250,8 +1231,8 @@
cleanerLock.notifyAll();
}
- lockGlobal(10 * 1000); // 10 seconds
-
+ configLock.writeLock().lock();
+ try {
cleanerThread.interrupt();
flushAndClose();
@@ -1261,6 +1242,9 @@
} catch (IOException e) {
Logger.error(this, "error writing store
config", e);
}
+ } finally {
+ configLock.writeLock().unlock();
+ }
}
}