r26841 - in trunk/freenet/src/freenet: client/async keys

[email protected] Wed, 15 Apr 2009 12:11:53 +0000
Newsgroups gmane.network.freenet.cvs
Message-ID <[email protected]>
Author: toad
Date: 2009-04-15 12:11:52 +0000 (Wed, 15 Apr 2009)
New Revision: 26841

Modified:
   trunk/freenet/src/freenet/client/async/SingleBlockInserter.java
   trunk/freenet/src/freenet/keys/ClientSSKBlock.java
Log:
Fix another db4o regression: Detect SSK collision with existing data.


Modified: trunk/freenet/src/freenet/client/async/SingleBlockInserter.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SingleBlockInserter.java	2009-04-15 12:04:48 UTC (rev 26840)
+++ trunk/freenet/src/freenet/client/async/SingleBlockInserter.java	2009-04-15 12:11:52 UTC (rev 26841)
@@ -5,6 +5,7 @@
 
 import java.io.IOException;
 import java.net.MalformedURLException;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -18,14 +19,17 @@
 import freenet.keys.ClientCHKBlock;
 import freenet.keys.ClientKey;
 import freenet.keys.ClientKeyBlock;
+import freenet.keys.ClientSSK;
+import freenet.keys.ClientSSKBlock;
 import freenet.keys.FreenetURI;
 import freenet.keys.InsertableClientSSK;
+import freenet.keys.KeyDecodeException;
 import freenet.keys.KeyEncodeException;
+import freenet.keys.KeyVerifyException;
 import freenet.keys.SSKEncodeException;
 import freenet.node.KeysFetchingLocally;
 import freenet.node.LowLevelPutException;
 import freenet.node.NodeClientCore;
-import freenet.node.NullSendableRequestItem;
 import freenet.node.RequestClient;
 import freenet.node.RequestScheduler;
 import freenet.node.SendableInsert;
@@ -461,10 +465,11 @@
 
 			public boolean send(NodeClientCore core, RequestScheduler sched, final ClientContext context, ChosenBlock req) {
 				// Ignore keyNum, key, since we're only sending one block.
+				ClientKeyBlock b;
+				ClientKey key = null;
+				if(logMINOR) Logger.minor(this, "Starting request: "+SingleBlockInserter.this);
+				BlockItem block = (BlockItem) req.token;
 				try {
-					if(logMINOR) Logger.minor(this, "Starting request: "+SingleBlockInserter.this);
-					BlockItem block = (BlockItem) req.token;
-					ClientKeyBlock b;
 					try {
 						b = innerEncode(context.random, block.uri, block.copyBucket, block.isMetadata, block.compressionCodec, block.sourceLength);
 					} catch (CHKEncodeException e) {
@@ -477,21 +482,20 @@
 						throw new LowLevelPutException(LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + e.getMessage(), e);
 					} catch (IOException e) {
 						throw new LowLevelPutException(LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + e.getMessage(), e);
-					} finally {
-						block.copyBucket.free();
 					}
 					if (b==null) {
 						Logger.error(this, "Asked to send empty block on "+SingleBlockInserter.this, new Exception("error"));
 						return false;
 					}
-					final ClientKey key = b.getClientKey();
+					key = b.getClientKey();
+					final ClientKey k = key;
 					if(block.persistent) {
 					context.jobRunner.queue(new DBJob() {
 
 						public void run(ObjectContainer container, ClientContext context) {
 							if(!container.ext().isStored(SingleBlockInserter.this)) return;
 							container.activate(SingleBlockInserter.this, 1);
-							onEncode(key, container, context);
+							onEncode(k, container, context);
 							container.deactivate(SingleBlockInserter.this, 1);
 						}
 						
@@ -500,7 +504,7 @@
 						context.mainExecutor.execute(new Runnable() {
 
 							public void run() {
-								onEncode(key, null, context);
+								onEncode(k, null, context);
 							}
 							
 						}, "Got URI");
@@ -508,9 +512,30 @@
 					}
 					core.realPut(b, req.cacheLocalRequests);
 				} catch (LowLevelPutException e) {
+					if(e.code == LowLevelPutException.COLLISION) {
+						// Collision
+						try {
+							ClientSSKBlock collided = (ClientSSKBlock) core.node.fetch((ClientSSK)key, true);
+							byte[] data = collided.memoryDecode(true);
+							byte[] inserting = BucketTools.toByteArray(block.copyBucket);
+							if(collided.isMetadata() == block.isMetadata && collided.getCompressionCodec() == block.compressionCodec && Arrays.equals(data, inserting)) {
+								if(logMINOR) Logger.minor(this, "Collided with identical data: "+SingleBlockInserter.this);
+								req.onInsertSuccess(context);
+								return true;
+							}
+						} catch (KeyVerifyException e1) {
+							Logger.error(this, "Caught "+e1+" when checking collision!", e1);
+						} catch (KeyDecodeException e1) {
+							Logger.error(this, "Caught "+e1+" when checking collision!", e1);
+						} catch (IOException e1) {
+							Logger.error(this, "Caught "+e1+" when checking collision!", e1);
+						}
+					}
 					req.onFailure(e, context);
 					if(logMINOR) Logger.minor(this, "Request failed: "+SingleBlockInserter.this+" for "+e);
 					return true;
+				} finally {
+					block.copyBucket.free();
 				}
 				if(logMINOR) Logger.minor(this, "Request succeeded: "+SingleBlockInserter.this);
 				req.onInsertSuccess(context);

Modified: trunk/freenet/src/freenet/keys/ClientSSKBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/ClientSSKBlock.java	2009-04-15 12:04:48 UTC (rev 26840)
+++ trunk/freenet/src/freenet/keys/ClientSSKBlock.java	2009-04-15 12:11:52 UTC (rev 26841)
@@ -110,13 +110,17 @@
 		return compressionAlgorithm;
 	}
 	
+	public byte[] memoryDecode() throws KeyDecodeException {
+		return memoryDecode(false);
+	}
+	
     /**
      * Decode into RAM, if short.
      * @throws KeyDecodeException 
      */
-	public byte[] memoryDecode() throws KeyDecodeException {
+	public byte[] memoryDecode(boolean dontDecompress) throws KeyDecodeException {
 		try {
-			ArrayBucket a = (ArrayBucket) decode(new ArrayBucketFactory(), 32*1024, false);
+			ArrayBucket a = (ArrayBucket) decode(new ArrayBucketFactory(), 32*1024, dontDecompress);
 			return BucketTools.toByteArray(a); // FIXME
 		} catch (IOException e) {
 			throw new Error(e);