Author: j16sdiz
Date: 2008-05-04 13:12:16 +0000 (Sun, 04 May 2008)
New Revision: 19734

Modified:
   
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java
Log:
proper locking


Modified: 
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java
===================================================================
--- 
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java  
    2008-05-04 13:11:55 UTC (rev 19733)
+++ 
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java  
    2008-05-04 13:12:16 UTC (rev 19734)
@@ -12,6 +12,8 @@
 import java.nio.channels.FileChannel;
 import java.text.DecimalFormat;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Random;

 import freenet.crypt.Digest;
@@ -107,7 +109,10 @@
                Entry entry;
                long offset = getOffsetFromPlainKey(routingKey, probeStoreSize);

-               lockEntry(offset);
+               if (!lockEntry(offset)) {
+                       Logger.error(this, "can't lock entry: " + offset);
+                       return null;
+               }
                try {
                        entry = readEntry(offset, routingKey);
                } catch (EOFException e) {
@@ -140,7 +145,11 @@
                }

                Entry entry = new Entry(routingKey, header, data);
-               lockEntry(entry.getOffset());
+               if (!lockEntry(entry.getOffset())) {
+                       Logger.error(this, "can't lock entry: " + 
entry.getOffset());
+                       incMisses();
+                       return;
+               }
                try {
                        writeEntry(entry);
                        incWrites();
@@ -399,6 +408,7 @@
                                storeRAF[i].setLength(entryTotalLength * 
(storeSize / FILE_SPLIT + 1));
                        }
                        storeFC[i] = storeRAF[i].getChannel();
+                       storeFC[i].lock();
                }
        }

@@ -581,6 +591,10 @@
        }

        // ------------- Locking
+       private boolean shutdown = false;
+       private boolean lockGlobal = false;
+       private Map lockMap = new HashMap();
+
        /**
         * Lock the entry // TODO locking
         * 
@@ -588,6 +602,29 @@
         * then one lock at a time (or deadlock may occur).
         */
        private boolean lockEntry(long offset) {
+               if (logDEBUG)
+                       Logger.debug(this, "try locking " + offset, new 
Exception());
+
+               Long lxr = new Long(offset);
+
+               try {
+                       synchronized (lockMap) {
+                               while (lockMap.containsKey(lxr) || lockGlobal) 
{ // while someone hold the lock
+                                       if (shutdown)
+                                               return false;
+
+                                       lockMap.wait();
+                               }
+
+                               lockMap.put(lxr, Thread.currentThread());
+                       }
+               } catch (InterruptedException e) {
+                       Logger.error(this, "lock interrupted", e);
+                       return false;
+               }
+
+               if (logDEBUG)
+                       Logger.debug(this, "locked " + offset, new Exception());
                return true;
        }

@@ -595,8 +632,56 @@
         * Unlock the entry // TODO locking
         */
        private void unlockEntry(long offset) {
+               if (logDEBUG)
+                       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) {
+                       try {
+                               long startTime = System.currentTimeMillis();
+
+                               while (!lockMap.isEmpty() || lockGlobal) {
+                                       lockMap.wait(timeout);
+
+                                       if (System.currentTimeMillis() - 
startTime > timeout)
+                                               return false;
+                               }
+
+                               lockGlobal = true;
+                               return true;
+                       } catch (InterruptedException e) {
+                               return false;
+                       }
+               }
+       }
+
+       /**
+        * Unlock the global lock
+        */
+       private void unlockGlobal() {
+               synchronized (lockMap) {
+                       lockGlobal = false;
+                       lockMap.notifyAll();
+               }
+       }
+
        // ------------- Hashing
        /**
         * <tt>0x10</tt> bytes of salt for better digestion, not too salty.


Reply via email to