Author: toad
Date: 2009-03-12 19:03:19 +0000 (Thu, 12 Mar 2009)
New Revision: 26009
Modified:
branches/db4o/freenet/src/freenet/client/async/SimpleManifestPutter.java
Log:
Fix leaks in inserting freesites. Not tested yet.
Modified:
branches/db4o/freenet/src/freenet/client/async/SimpleManifestPutter.java
===================================================================
--- branches/db4o/freenet/src/freenet/client/async/SimpleManifestPutter.java
2009-03-12 19:02:46 UTC (rev 26008)
+++ branches/db4o/freenet/src/freenet/client/async/SimpleManifestPutter.java
2009-03-12 19:03:19 UTC (rev 26009)
@@ -3,6 +3,7 @@
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -108,7 +109,22 @@
}
public void cancel(ObjectContainer container, ClientContext
context) {
- super.cancel();
+ if(Logger.shouldLog(Logger.MINOR, this))
+ Logger.minor(this, "Cancelling "+this, new
Exception("debug"));
+ ClientPutState oldState = null;
+ synchronized(this) {
+ if(cancelled) return;
+ if(finished) return;
+ super.cancel();
+ oldState = currentState;
+ }
+ if(persistent()) {
+ container.store(this);
+ if(oldState != null)
+ container.activate(oldState, 1);
+ }
+ if(oldState != null) oldState.cancel(container,
context);
+ onFailure(new
InsertException(InsertException.CANCELLED), null, container, context);
}
@Override
@@ -140,6 +156,39 @@
runningPutHandlers.remove(this);
if(persistent)
container.store(runningPutHandlers);
+
+ if(persistent)
+
container.activate(putHandlersWaitingForMetadata, 2);
+
if(putHandlersWaitingForMetadata.contains(this)) {
+
putHandlersWaitingForMetadata.remove(this);
+
container.store(putHandlersWaitingForMetadata);
+ Logger.error(this, "PutHandler was in
waitingForMetadata in onSuccess() on "+this+" for "+SimpleManifestPutter.this);
+ }
+
+ if(persistent)
+
container.deactivate(putHandlersWaitingForMetadata, 1);
+ if(persistent)
+ container.activate(waitingForBlockSets,
2);
+ if(waitingForBlockSets.contains(this)) {
+ waitingForBlockSets.remove(this);
+ container.store(waitingForBlockSets);
+ Logger.error(this, "PutHandler was in
waitingForBlockSets in onSuccess() on "+this+" for "+SimpleManifestPutter.this);
+ }
+ if(persistent)
+
container.deactivate(waitingForBlockSets, 1);
+
+ if(persistent)
+
container.deactivate(putHandlersWaitingForFetchable, 1);
+ if(persistent)
+
container.activate(putHandlersWaitingForFetchable, 2);
+
if(putHandlersWaitingForFetchable.contains(this)) {
+
putHandlersWaitingForFetchable.remove(this);
+
container.store(putHandlersWaitingForFetchable);
+ Logger.error(this, "PutHandler was in
waitingForFetchable in onSuccess() on "+this+" for "+SimpleManifestPutter.this);
+ }
+ if(persistent)
+
container.deactivate(putHandlersWaitingForFetchable, 1);
+
if(!runningPutHandlers.isEmpty()) {
if(logMINOR) {
Logger.minor(this, "Running put
handlers: "+runningPutHandlers.size());
@@ -164,7 +213,7 @@
state.removeFrom(container, context);
}
if(insertedAllFiles)
- insertedAllFiles(container);
+ insertedAllFiles(container, context);
if(persistent) {
container.deactivate(runningPutHandlers, 1);
container.deactivate(SimpleManifestPutter.this,
1);
@@ -187,7 +236,7 @@
if(logMINOR) Logger.minor(this, "Failed: "+this+" -
"+e, e);
if(persistent)
container.activate(SimpleManifestPutter.this,
1);
- fail(e, container);
+ fail(e, container, context);
if(persistent)
container.deactivate(SimpleManifestPutter.this,
1);
}
@@ -271,10 +320,10 @@
try {
resolve(e, container, context);
} catch (IOException e1) {
- fail(new
InsertException(InsertException.BUCKET_ERROR, e1, null), container);
+ fail(new
InsertException(InsertException.BUCKET_ERROR, e1, null), container, context);
return;
} catch (InsertException e1) {
- fail(e1, container);
+ fail(e1, container, context);
}
}
}
@@ -386,14 +435,51 @@
// Ignore
}
+ public void clearMetadata(ObjectContainer container) {
+ metadata = null;
+ container.store(this);
+ }
+
+ public void removeFrom(ObjectContainer container, ClientContext
context) {
+ SingleFileInserter oldSFI;
+ ClientPutState oldState;
+ synchronized(this) {
+ oldSFI = origSFI;
+ oldState = currentState;
+ oldSFI = null;
+ currentState = null;
+ }
+ if(oldSFI != null) {
+ Logger.error(this, "origSFI is set in
removeFrom() on "+this+" for "+SimpleManifestPutter.this);
+ oldSFI.cancel(container, context);
+ oldSFI.removeFrom(container, context);
+ if(oldState == oldSFI) oldState = null;
+ }
+ if(oldState != null) {
+ Logger.error(this, "currentState is set in
removeFrom() on "+this+" for "+SimpleManifestPutter.this);
+ currentState.cancel(container, context);
+ currentState.removeFrom(container, context);
+ }
+ if(cm != null) {
+ cm.removeFrom(container);
+ }
+ if(metadata != null) {
+ // Possible if cancelled
+ Logger.error(this, "Metadata is set in
removeFrom() on "+this+" for "+SimpleManifestPutter.this);
+ metadata.removeFrom(container);
+ }
+ // Data is responsibility of original caller (usually
ClientPutDir), we don't support freeData atm
+ super.removeFrom(container, context);
+ }
+
}
static boolean logMINOR;
- private final HashMap<String,Object> putHandlersByName;
- private final HashSet<PutHandler> runningPutHandlers;
- private final HashSet<PutHandler> putHandlersWaitingForMetadata;
- private final HashSet<PutHandler> waitingForBlockSets;
- private final HashSet<PutHandler> putHandlersWaitingForFetchable;
+ private HashMap<String,Object> putHandlersByName;
+ private HashSet<PutHandler> runningPutHandlers;
+ private HashSet<PutHandler> putHandlersWaitingForMetadata;
+ private HashSet<PutHandler> waitingForBlockSets;
+ private HashSet<PutHandler> putHandlersWaitingForFetchable;
private FreenetURI finalURI;
private FreenetURI targetURI;
private boolean finished;
@@ -413,7 +499,7 @@
private final static String[] defaultDefaultNames =
new String[] { "index.html", "index.htm", "default.html",
"default.htm" };
private int bytesOnZip;
- private LinkedList<PutHandler> elementsToPutInArchive;
+ private ArrayList<PutHandler> elementsToPutInArchive;
private boolean fetchable;
private final boolean earlyEncode;
@@ -435,7 +521,7 @@
waitingForBlockSets = new HashSet<PutHandler>();
metadataPuttersByMetadata = new
HashMap<Metadata,SingleFileInserter>();
metadataPuttersUnfetchable = new
HashMap<Metadata,SingleFileInserter>();
- elementsToPutInArchive = new LinkedList<PutHandler>();
+ elementsToPutInArchive = new ArrayList<PutHandler>();
makePutHandlers(manifestElements, putHandlersByName);
checkZips();
}
@@ -537,7 +623,7 @@
ph = new PutHandler(this, name,
ZipPrefix+element.fullName, cm, data);
if(logMINOR)
Logger.minor(this,
"Putting file into container: "+element.fullName+" : "+ph);
-
elementsToPutInArchive.addLast(ph);
+ elementsToPutInArchive.add(ph);
numberOfFiles++;
totalSize += data.size();
} else {
@@ -612,7 +698,7 @@
if(defaultName != null) {
Metadata meta = (Metadata)
namesToByteArrays.get(defaultName);
if(meta == null) {
- fail(new
InsertException(InsertException.INVALID_URI, "Default name "+defaultName+" does
not exist", null), container);
+ fail(new
InsertException(InsertException.INVALID_URI, "Default name "+defaultName+" does
not exist", null), container, context);
return;
}
namesToByteArrays.put("", meta);
@@ -633,9 +719,6 @@
container.store(this);
}
resolveAndStartBase(container, context);
- if(persistent()) {
- container.deactivate(putHandlersByName, 1);
- }
}
@@ -661,7 +744,7 @@
Logger.minor(this, "Metadata bucket is
"+bucket.size()+" bytes long");
break;
} catch (IOException e) {
- fail(new
InsertException(InsertException.BUCKET_ERROR, e, null), container);
+ fail(new
InsertException(InsertException.BUCKET_ERROR, e, null), container, context);
return;
} catch (MetadataUnresolvedException e) {
try {
@@ -675,12 +758,12 @@
} catch (IOException e1) {
if(persistent())
container.deactivate(baseMetadata, 1);
- fail(new
InsertException(InsertException.BUCKET_ERROR, e, null), container);
+ fail(new
InsertException(InsertException.BUCKET_ERROR, e, null), container, context);
return;
} catch (InsertException e2) {
if(persistent())
container.deactivate(baseMetadata, 1);
- fail(e2, container);
+ fail(e2, container, context);
return;
}
}
@@ -724,7 +807,7 @@
isMetadata = false;
insertAsArchiveManifest = true;
} catch (IOException e) {
- fail(new
InsertException(InsertException.BUCKET_ERROR, e, null), container);
+ fail(new
InsertException(InsertException.BUCKET_ERROR, e, null), container, context);
if(persistent())
container.deactivate(baseMetadata, 1);
return;
@@ -752,7 +835,7 @@
}
metadataInserter.start(null, container, context);
} catch (InsertException e) {
- fail(e, container);
+ fail(e, container, context);
return;
}
if(persistent()) {
@@ -908,6 +991,7 @@
Metadata meta = ph.metadata;
if(ph.metadata == null)
Logger.error(this, "Metadata for
"+name+" : "+ph+" is null");
+ ph.clearMetadata(container);
if(persistent())
container.activate(meta, 100);
Logger.minor(this, "Putting "+name);
@@ -928,7 +1012,7 @@
}
}
- private void insertedAllFiles(ObjectContainer container) {
+ private void insertedAllFiles(ObjectContainer container, ClientContext
context) {
if(logMINOR) Logger.minor(this, "Inserted all files");
synchronized(this) {
insertedAllFiles = true;
@@ -948,10 +1032,14 @@
}
if(persistent())
container.store(this);
- complete(container);
+ complete(container, context);
}
- private void complete(ObjectContainer container) {
+ private void complete(ObjectContainer container, ClientContext context)
{
+ // FIXME we could remove the put handlers after inserting all
files but not having finished the insert of the manifest
+ // However it would complicate matters for no real gain in most
cases...
+ // Also doing it this way means we don't need to worry about
+ if(persistent()) removePutHandlers(container, context);
boolean deactivateCB = false;
if(persistent()) {
deactivateCB = !container.ext().isActive(cb);
@@ -962,16 +1050,127 @@
container.deactivate(cb, 1);
}
- private void fail(InsertException e, ObjectContainer container) {
+ private void fail(InsertException e, ObjectContainer container,
ClientContext context) {
// Cancel all, then call the callback
cancelAndFinish(container);
+ if(persistent()) removePutHandlers(container, context);
if(persistent())
container.activate(cb, 1);
cb.onFailure(e, this, container);
}
+ private void removePutHandlers(ObjectContainer container, ClientContext
context) {
+ container.activate(putHandlersByName, 2);
+ container.activate(runningPutHandlers, 2);
+ container.activate(putHandlersWaitingForMetadata, 2);
+ container.activate(waitingForBlockSets, 2);
+ container.activate(putHandlersWaitingForFetchable, 2);
+ container.activate(elementsToPutInArchive, 2);
+ removePutHandlersByName(container, context, putHandlersByName);
+ putHandlersByName = null;
+
+ if(!runningPutHandlers.isEmpty()) {
+ Logger.error(this, "Running put handlers not part of
putHandlersByName: "+runningPutHandlers.size()+" in removePutHandlers() on
"+this, new Exception("error"));
+ for(PutHandler handler : runningPutHandlers) {
+ container.activate(handler, 1);
+ Logger.error(this, "Still running, but not in
putHandlersByName: "+handler);
+ handler.cancel();
+ handler.removeFrom(container, context);
+ }
+ runningPutHandlers.clear();
+ }
+ if(!putHandlersWaitingForMetadata.isEmpty()) {
+ Logger.error(this, "Put handlers waiting for metadata,
not part of putHandlersByName: "+runningPutHandlers.size()+" in
removePutHandlers() on "+this, new Exception("error"));
+ for(PutHandler handler : putHandlersWaitingForMetadata)
{
+ container.activate(handler, 1);
+ Logger.error(this, "Still waiting for metadata,
but not in putHandlersByName: "+handler);
+ handler.cancel();
+ handler.removeFrom(container, context);
+ }
+ putHandlersWaitingForMetadata.clear();
+ }
+ if(!waitingForBlockSets.isEmpty()) {
+ Logger.error(this, "Put handlers waiting for block
sets, not part of putHandlersByName: "+runningPutHandlers.size()+" in
removePutHandlers() on "+this, new Exception("error"));
+ for(PutHandler handler : waitingForBlockSets) {
+ container.activate(handler, 1);
+ Logger.error(this, "Still waiting for block
set, but not in putHandlersByName: "+handler);
+ handler.cancel();
+ handler.removeFrom(container, context);
+ waitingForBlockSets.clear();
+ }
+ }
+ if(!putHandlersWaitingForFetchable.isEmpty()) {
+ Logger.error(this, "Put handlers waiting for fetchable,
not part of putHandlersByName: "+runningPutHandlers.size()+" in
removePutHandlers() on "+this, new Exception("error"));
+ for(PutHandler handler :
putHandlersWaitingForFetchable) {
+ container.activate(handler, 1);
+ Logger.error(this, "Still waiting for
fetchable, but not in putHandlersByName: "+handler);
+ handler.cancel();
+ handler.removeFrom(container, context);
+ putHandlersWaitingForFetchable.clear();
+ }
+ }
+ if(!elementsToPutInArchive.isEmpty()) {
+ Logger.error(this, "Elements to put in archive, not
part of putHandlersByName: "+runningPutHandlers.size()+" in removePutHandlers()
on "+this, new Exception("error"));
+ for(PutHandler handler : elementsToPutInArchive) {
+ container.activate(handler, 1);
+ Logger.error(this, "To put in archive, but not
in putHandlersByName: "+handler);
+ handler.removeFrom(container, context);
+ elementsToPutInArchive.clear();
+ }
+ }
+
+ container.delete(runningPutHandlers);
+ container.delete(putHandlersWaitingForMetadata);
+ container.delete(waitingForBlockSets);
+ container.delete(putHandlersWaitingForFetchable);
+ container.delete(elementsToPutInArchive);
+ runningPutHandlers = null;
+ putHandlersWaitingForMetadata = null;
+ waitingForBlockSets = null;
+ putHandlersWaitingForFetchable = null;
+ elementsToPutInArchive = null;
+ container.store(this);
+ }
+
/**
+ * Remove all PutHandler's from the given putHandlersByName sub-map.
+ * Remove the PutHandler's themselves also, remove them from and
complain about
+ * runningPutHandlers, putHandlersWaitingForMetadata,
waitingForBlockSets,
+ * putHandlersWaitingForFetchable, which must have been activated by
the caller.
+ * @param container
+ * @param putHandlersByName
+ */
+ private void removePutHandlersByName(ObjectContainer container,
ClientContext context, HashMap<String, Object> putHandlersByName) {
+ for(Map.Entry<String, Object> entry :
putHandlersByName.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ if(value instanceof PutHandler) {
+ PutHandler handler = (PutHandler) value;
+ container.activate(handler, 1);
+ if(runningPutHandlers.remove(handler))
+ container.store(runningPutHandlers);
+
if(putHandlersWaitingForMetadata.remove(handler))
+
container.store(putHandlersWaitingForMetadata);
+ if(waitingForBlockSets.remove(handler))
+ container.store(waitingForBlockSets);
+
if(putHandlersWaitingForFetchable.remove(handler))
+
container.store(putHandlersWaitingForFetchable);
+ if(elementsToPutInArchive.remove(handler))
+ container.store(elementsToPutInArchive);
+ handler.removeFrom(container, context);
+ } else {
+ HashMap<String, Object> subMap =
(HashMap<String, Object>) value;
+ container.activate(subMap, 2);
+ removePutHandlersByName(container, context,
subMap);
+ }
+ container.delete(key);
+ }
+ putHandlersByName.clear();
+ container.delete(putHandlersByName);
+ }
+
+ /**
* Cancel all running inserters and set finished to true.
*/
private void cancelAndFinish(ObjectContainer container) {
@@ -996,7 +1195,7 @@
super.cancel();
if(persistent())
container.store(this);
- fail(new InsertException(InsertException.CANCELLED), container);
+ fail(new InsertException(InsertException.CANCELLED), container,
context);
}
public void onSuccess(ClientPutState state, ObjectContainer container,
ClientContext context) {
@@ -1031,12 +1230,12 @@
container.store(this);
container.deactivate(metadataPuttersByMetadata, 1);
}
- complete(container);
+ complete(container, context);
}
public void onFailure(InsertException e, ClientPutState state,
ObjectContainer container, ClientContext context) {
logMINOR = Logger.shouldLog(Logger.MINOR, this);
- fail(e, container);
+ fail(e, container, context);
}
public void onEncode(BaseClientKey key, ClientPutState state,
ObjectContainer container, ClientContext context) {
@@ -1045,7 +1244,7 @@
if(logMINOR) Logger.minor(this, "Got metadata key:
"+finalURI);
if(persistent())
container.activate(cb, 1);
- cb.onGeneratedURI(finalURI, this, container);
+ cb.onGeneratedURI(persistent() ? finalURI.clone() :
finalURI, this, container);
if(persistent())
container.deactivate(cb, 1);
if(persistent())
@@ -1285,5 +1484,58 @@
// Ignore
}
+ @Override
+ public void removeFrom(ObjectContainer container, ClientContext
context) {
+ if(putHandlersByName != null) {
+ Logger.error(this, "Put handlers list still present in
removeFrom() on "+this);
+ removePutHandlers(container, context);
+ }
+ if(finalURI != FreenetURI.EMPTY_CHK_URI)
+ finalURI.removeFrom(container);
+ if(targetURI != FreenetURI.EMPTY_CHK_URI)
+ targetURI.removeFrom(container);
+ container.activate(ctx, 1);
+ ctx.removeFrom(container);
+ container.activate(metadataPuttersByMetadata, 2);
+ container.activate(metadataPuttersUnfetchable, 2);
+ if(!metadataPuttersByMetadata.isEmpty()) {
+ Logger.error(this, "Metadata putters by metadata not
empty in removeFrom() on "+this);
+ for(Map.Entry<Metadata, SingleFileInserter> entry :
metadataPuttersByMetadata.entrySet()) {
+ Metadata meta = entry.getKey();
+ container.activate(meta, 1);
+ SingleFileInserter sfi = entry.getValue();
+ container.activate(sfi, 1);
+ metadataPuttersUnfetchable.remove(meta);
+ Logger.error(this, "Metadata putters not empty:
"+sfi+" for "+this);
+ sfi.cancel(container, context);
+ sfi.removeFrom(container, context);
+ }
+ }
+ if(!metadataPuttersUnfetchable.isEmpty()) {
+ Logger.error(this, "Metadata putters unfetchable by
metadata not empty in removeFrom() on "+this);
+ for(Map.Entry<Metadata, SingleFileInserter> entry :
metadataPuttersByMetadata.entrySet()) {
+ Metadata meta = entry.getKey();
+ container.activate(meta, 1);
+ SingleFileInserter sfi = entry.getValue();
+ container.activate(sfi, 1);
+ metadataPuttersUnfetchable.remove(meta);
+ Logger.error(this, "Metadata putters
unfetchable not empty: "+sfi+" for "+this);
+ sfi.cancel(container, context);
+ sfi.removeFrom(container, context);
+ }
+ }
+ metadataPuttersByMetadata.clear();
+ metadataPuttersUnfetchable.clear();
+ container.delete(metadataPuttersByMetadata);
+ container.delete(metadataPuttersUnfetchable);
+ if(baseMetadata != null) {
+ container.activate(baseMetadata, 1);
+ baseMetadata.removeFrom(container);
+ }
+ container.activate(runGotAllMetadata, 1);
+ container.delete(runGotAllMetadata);
+ super.removeFrom(container, context);
+ }
+
}
_______________________________________________
cvs mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs