Author: toad
Date: 2006-01-26 17:55:28 +0000 (Thu, 26 Jan 2006)
New Revision: 7935

Modified:
   trunk/freenet/src/freenet/node/Version.java
   trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
Log:
386:
Fix datastore deadlock under load.

Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-01-26 16:27:13 UTC (rev 
7934)
+++ trunk/freenet/src/freenet/node/Version.java 2006-01-26 17:55:28 UTC (rev 
7935)
@@ -20,10 +20,10 @@
        public static final String protocolVersion = "1.0";

        /** The build number of the current revision */
-       public static final int buildNumber = 385;
+       public static final int buildNumber = 386;

        /** Oldest build of Fred we will talk to */
-       public static final int lastGoodBuild = 381;
+       public static final int lastGoodBuild = 386;

        /** The highest reported build of fred */
        public static int highestSeenBuild = buildNumber;

Modified: trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
===================================================================
--- trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2006-01-26 
16:27:13 UTC (rev 7934)
+++ trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2006-01-26 
17:55:28 UTC (rev 7935)
@@ -143,11 +143,20 @@
        DatabaseEntry routingkeyDBE = new DatabaseEntry(routingkey);
        DatabaseEntry blockDBE = new DatabaseEntry();
        Cursor c = null;
+       Transaction t = null;
        try{
-               Transaction t = environment.beginTransaction(null,null);
+               t = environment.beginTransaction(null,null);
                c = chkDB.openCursor(t,null);
-               
-               if(c.getSearchKey(routingkeyDBE,blockDBE,LockMode.DEFAULT)
+
+               /**
+                * We will have to write, unless both dontPromote and the key 
is valid.
+                * The lock only applies to this record, so it's not a big 
problem for our use.
+                * What *IS* a big problem is that if we take a 
LockMode.DEFAULT, and two threads
+                * access the same key, they will both take the read lock, and 
then both try to
+                * take the write lock. Neither can relinquish the read in 
order for the other to
+                * take the write, so we're screwed.
+                */
+               if(c.getSearchKey(routingkeyDBE,blockDBE,LockMode.RMW)
                                !=OperationStatus.SUCCESS) {
                        c.close();
                        t.abort();
@@ -197,10 +206,12 @@
                    return null;
                }
                return block;
-       }catch(Exception ex) {  // FIXME: ugly  
+       }catch(Throwable ex) {  // FIXME: ugly  
                if(c!=null) {
                        try{c.close();}catch(DatabaseException ex2){}
                }
+               if(t!=null)
+                       try{t.abort();}catch(DatabaseException ex2){}
                Logger.error(this, "Caught "+ex, ex);
                ex.printStackTrace();
                throw new IOException(ex.getMessage());
@@ -223,11 +234,12 @@
        DatabaseEntry routingkeyDBE = new DatabaseEntry(routingkey);
        DatabaseEntry blockDBE = new DatabaseEntry();
        Cursor c = null;
+       Transaction t = null;
        try{
-               Transaction t = environment.beginTransaction(null,null);
+               t = environment.beginTransaction(null,null);
                c = chkDB.openCursor(t,null);

-               if(c.getSearchKey(routingkeyDBE,blockDBE,LockMode.DEFAULT)
+               if(c.getSearchKey(routingkeyDBE,blockDBE,LockMode.RMW)
                                !=OperationStatus.SUCCESS) {
                        c.close();
                        t.abort();
@@ -277,10 +289,13 @@
                    return null;
                }
                return block;
-       }catch(Exception ex) {  // FIXME: ugly  
+       }catch(Throwable ex) {  // FIXME: ugly  
                if(c!=null) {
                        try{c.close();}catch(DatabaseException ex2){}
                }
+               if(t!=null) {
+                       try{t.abort();}catch(DatabaseException ex2){}
+               }
                Logger.error(this, "Caught "+ex, ex);
                ex.printStackTrace();
                throw new IOException(ex.getMessage());
@@ -304,11 +319,12 @@
        DatabaseEntry routingkeyDBE = new DatabaseEntry(hash);
        DatabaseEntry blockDBE = new DatabaseEntry();
        Cursor c = null;
+       Transaction t = null;
        try{
-               Transaction t = environment.beginTransaction(null,null);
+               t = environment.beginTransaction(null,null);
                c = chkDB.openCursor(t,null);

-               if(c.getSearchKey(routingkeyDBE,blockDBE,LockMode.DEFAULT)
+               if(c.getSearchKey(routingkeyDBE,blockDBE,LockMode.RMW)
                                !=OperationStatus.SUCCESS) {
                        c.close();
                        t.abort();
@@ -329,6 +345,8 @@
                                block = new DSAPublicKey(data);
                        } catch (IOException e) {
                                Logger.error(this, "Could not read key");
+                               c.close();
+                               t.abort();
                                return null;
                        }

@@ -360,10 +378,13 @@
                    Logger.minor(this, "Data: "+data.length+" bytes, hash 
"+data);

                return block;
-       }catch(Exception ex) {  // FIXME: ugly  
+       }catch(Throwable ex) {  // FIXME: ugly  
                if(c!=null) {
                        try{c.close();}catch(DatabaseException ex2){}
                }
+               if(t!=null) {
+                       try{t.abort();}catch(DatabaseException ex2){}
+               }
                Logger.error(this, "Caught "+ex, ex);
                ex.printStackTrace();
                throw new IOException(ex.getMessage());
@@ -436,7 +457,7 @@
                Logger.minor(this, "Headers: "+header.length+" bytes, hash 
"+Fields.hashCode(header));
                Logger.minor(this, "Data: "+data.length+" bytes, hash 
"+Fields.hashCode(data));

-        }catch(Exception ex) {  // FIXME: ugly  
+        }catch(Throwable ex) {  // FIXME: ugly  
                if(t!=null){
                        try{t.abort();}catch(DatabaseException ex2){};
                }


Reply via email to