Author: toad
Date: 2006-05-12 18:31:58 +0000 (Fri, 12 May 2006)
New Revision: 8683
Added:
trunk/freenet/src/freenet/store/KeyCollisionException.java
Modified:
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/RequestSender.java
trunk/freenet/src/freenet/node/SSKInsertHandler.java
trunk/freenet/src/freenet/node/Version.java
trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
trunk/freenet/src/freenet/store/FreenetStore.java
Log:
703: Major bugfix to datastore.
Bug will have lead to occasionally losing slots in the datastore, potentially
wasting large amounts of space.
RECOMMEND DATASTORE RESET, but please try to do so over a period of days, not
all at once.
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2006-05-12 17:42:18 UTC (rev
8682)
+++ trunk/freenet/src/freenet/node/Node.java 2006-05-12 18:31:58 UTC (rev
8683)
@@ -89,6 +89,7 @@
import freenet.pluginmanager.PluginManager;
import freenet.store.BerkeleyDBFreenetStore;
import freenet.store.FreenetStore;
+import freenet.store.KeyCollisionException;
import freenet.support.Base64;
import freenet.support.Bucket;
import freenet.support.BucketFactory;
@@ -1618,10 +1619,12 @@
synchronized(this) {
if(cache) {
try {
- sskDatastore.put(block);
+ sskDatastore.put(block, false);
} catch (IOException e) {
Logger.error(this, "Datastore failure: "+e, e);
- }
+ } catch (KeyCollisionException e) {
+ throw new
LowLevelPutException(LowLevelPutException.COLLISION);
+ }
}
is = makeInsertSender(block,
MAX_HTL, uid, null, false, lm.getLocation().getValue(),
cache);
@@ -1674,7 +1677,15 @@
if(is.hasCollided()) {
// Store it locally so it can be fetched immediately, and
overwrites any locally inserted.
- store(is.getBlock());
+ try {
+ synchronized(this) {
+ sskDatastore.put(is.getBlock(), true);
+ }
+ } catch (KeyCollisionException e) {
+ // Impossible
+ } catch (IOException e) {
+ Logger.error(this, "Datastore failure: "+e, e);
+ }
throw new LowLevelPutException(LowLevelPutException.COLLISION);
}
@@ -2034,9 +2045,9 @@
}
}
- public synchronized void store(SSKBlock block) {
+ public synchronized void store(SSKBlock block) throws
KeyCollisionException {
try {
- sskDatastore.put(block);
+ sskDatastore.put(block, false);
cacheKey(((NodeSSK)block.getKey()).getPubKeyHash(),
((NodeSSK)block.getKey()).getPubKey());
} catch (IOException e) {
Logger.error(this, "Cannot store data: "+e, e);
Modified: trunk/freenet/src/freenet/node/RequestSender.java
===================================================================
--- trunk/freenet/src/freenet/node/RequestSender.java 2006-05-12 17:42:18 UTC
(rev 8682)
+++ trunk/freenet/src/freenet/node/RequestSender.java 2006-05-12 18:31:58 UTC
(rev 8683)
@@ -18,6 +18,7 @@
import freenet.keys.NodeSSK;
import freenet.keys.SSKBlock;
import freenet.keys.SSKVerifyException;
+import freenet.store.KeyCollisionException;
import freenet.support.Logger;
import freenet.support.ShortBuffer;
@@ -398,6 +399,8 @@
Logger.error(this, "Failed to verify: "+e+" from
"+next, e);
finish(VERIFY_FAILURE, next);
return;
+ } catch (KeyCollisionException e) {
+ Logger.normal(this, "Collision on "+this);
}
}
@@ -427,7 +430,11 @@
node.store(block);
} else if (key instanceof NodeSSK) {
SSKBlock block = new SSKBlock(data, headers, (NodeSSK)key,
false);
- node.store(block);
+ try {
+ node.store(block);
+ } catch (KeyCollisionException e) {
+ Logger.normal(this, "Collision on "+this);
+ }
}
}
Modified: trunk/freenet/src/freenet/node/SSKInsertHandler.java
===================================================================
--- trunk/freenet/src/freenet/node/SSKInsertHandler.java 2006-05-12
17:42:18 UTC (rev 8682)
+++ trunk/freenet/src/freenet/node/SSKInsertHandler.java 2006-05-12
18:31:58 UTC (rev 8683)
@@ -12,6 +12,7 @@
import freenet.keys.NodeSSK;
import freenet.keys.SSKBlock;
import freenet.keys.SSKVerifyException;
+import freenet.store.KeyCollisionException;
import freenet.support.Logger;
import freenet.support.ShortBuffer;
@@ -291,7 +292,11 @@
Logger.minor(this, "Finishing");
if(canCommit) {
- node.store(block);
+ try {
+ node.store(block);
+ } catch (KeyCollisionException e) {
+ Logger.normal(this, "Collision on "+this);
+ }
}
}
Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-05-12 17:42:18 UTC (rev
8682)
+++ trunk/freenet/src/freenet/node/Version.java 2006-05-12 18:31:58 UTC (rev
8683)
@@ -18,7 +18,7 @@
public static final String protocolVersion = "1.0";
/** The build number of the current revision */
- private static final int buildNumber = 702;
+ private static final int buildNumber = 703;
/** Oldest build of Fred we will talk to */
private static final int lastGoodBuild = 591;
Modified: trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java
===================================================================
--- trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2006-05-12
17:42:18 UTC (rev 8682)
+++ trunk/freenet/src/freenet/store/BerkeleyDBFreenetStore.java 2006-05-12
18:31:58 UTC (rev 8683)
@@ -411,10 +411,84 @@
// return null;
}
- /**
+ public void put(CHKBlock b) throws IOException {
+ NodeCHK chk = (NodeCHK) b.getKey();
+ CHKBlock oldBlock = fetch(chk, false);
+ if(oldBlock != null)
+ return;
+ innerPut(b);
+ }
+
+ public void put(SSKBlock b, boolean overwrite) throws IOException,
KeyCollisionException {
+ NodeSSK ssk = (NodeSSK) b.getKey();
+ SSKBlock oldBlock = fetch(ssk, false);
+ if(oldBlock != null) {
+ if(!b.equals(oldBlock)) {
+ if(!overwrite)
+ throw new KeyCollisionException();
+ else {
+ if(overwrite(b)) {
+ fetch(ssk, false); // promote it
+ return;
+ }
+ }
+ }
+ return;
+ }
+ innerPut(b);
+ }
+
+ private boolean overwrite(SSKBlock b) throws IOException {
+ NodeSSK chk = (NodeSSK) b.getKey();
+ byte[] routingkey = chk.getRoutingKey();
+ DatabaseEntry routingkeyDBE = new DatabaseEntry(routingkey);
+ DatabaseEntry blockDBE = new DatabaseEntry();
+ Cursor c = null;
+ Transaction t = null;
+ try{
+ t = environment.beginTransaction(null,null);
+ c = chkDB.openCursor(t,null);
+
+ if(c.getSearchKey(routingkeyDBE,blockDBE,LockMode.RMW)
+ !=OperationStatus.SUCCESS) {
+ c.close();
+ t.abort();
+ return false;
+ }
+
+ StoreBlock storeBlock = (StoreBlock)
storeBlockTupleBinding.entryToObject(blockDBE);
+
+ byte[] header = b.getRawHeaders();
+ byte[] data = b.getRawData();
+ synchronized(chkStore) {
+
chkStore.seek(storeBlock.offset*(long)(dataBlockSize+headerBlockSize));
+
+ chkStore.write(header);
+ chkStore.write(data);
+ }
+
+ } catch(Throwable ex) { // FIXME: ugly
+ if(c!=null) {
+ try{c.close();}catch(DatabaseException ex2){}
+
+ }
+ if(t!=null) {
+ try{t.abort();}catch(DatabaseException ex2){}
+ }
+
+ checkSecondaryDatabaseError(ex);
+ Logger.error(this, "Caught "+ex, ex);
+ ex.printStackTrace();
+ throw new IOException(ex.getMessage());
+ }
+
+ return true;
+ }
+
+ /**
* Store a block.
*/
- public void put(KeyBlock block) throws IOException
+ void innerPut(KeyBlock block) throws IOException
{
if(closed)
return;
Modified: trunk/freenet/src/freenet/store/FreenetStore.java
===================================================================
--- trunk/freenet/src/freenet/store/FreenetStore.java 2006-05-12 17:42:18 UTC
(rev 8682)
+++ trunk/freenet/src/freenet/store/FreenetStore.java 2006-05-12 18:31:58 UTC
(rev 8683)
@@ -35,8 +35,15 @@
/**
* Store a block.
+ * @throws KeyCollisionException If the key already exists but has
different contents.
+ * @param ignoreAndOverwrite If true, overwrite old content rather than
throwing a KeyCollisionException.
*/
- public void put(KeyBlock block) throws IOException;
+ public void put(SSKBlock block, boolean ignoreAndOverwrite) throws
IOException, KeyCollisionException;
+
+ /**
+ * Store a block.
+ */
+ public void put(CHKBlock block) throws IOException;
/**
* Store a public key.
Added: trunk/freenet/src/freenet/store/KeyCollisionException.java
===================================================================
--- trunk/freenet/src/freenet/store/KeyCollisionException.java 2006-05-12
17:42:18 UTC (rev 8682)
+++ trunk/freenet/src/freenet/store/KeyCollisionException.java 2006-05-12
18:31:58 UTC (rev 8683)
@@ -0,0 +1,5 @@
+package freenet.store;
+
+public class KeyCollisionException extends Exception {
+
+}