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){};
}