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();
+                       }
                }
        }



Reply via email to