Author: xor
Date: 2008-11-16 15:53:42 +0000 (Sun, 16 Nov 2008)
New Revision: 23645
Modified:
trunk/plugins/WoT/IdentityInserter.java
trunk/plugins/WoT/WoT.java
trunk/plugins/WoT/introduction/IntroductionClient.java
trunk/plugins/WoT/introduction/IntroductionPuzzle.java
trunk/plugins/WoT/introduction/IntroductionServer.java
Log:
Finally fix plugin unloading: Make all inserts & requests non-blocking.
Blocking inserts/requests do not care about Thread.interrupt().
Modified: trunk/plugins/WoT/IdentityInserter.java
===================================================================
--- trunk/plugins/WoT/IdentityInserter.java 2008-11-16 14:34:36 UTC (rev
23644)
+++ trunk/plugins/WoT/IdentityInserter.java 2008-11-16 15:53:42 UTC (rev
23645)
@@ -9,13 +9,16 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.Iterator;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import plugins.WoT.exceptions.InvalidParameterException;
+import plugins.WoT.introduction.IntroductionPuzzle;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
@@ -23,10 +26,18 @@
import com.db4o.ext.Db4oIOException;
import freenet.client.ClientMetadata;
+import freenet.client.FetchException;
+import freenet.client.FetchResult;
import freenet.client.HighLevelSimpleClient;
import freenet.client.InsertBlock;
+import freenet.client.InsertContext;
import freenet.client.InsertException;
+import freenet.client.async.BaseClientPutter;
+import freenet.client.async.ClientCallback;
+import freenet.client.async.ClientGetter;
+import freenet.client.async.ClientPutter;
import freenet.keys.FreenetURI;
+import freenet.node.RequestStarter;
import freenet.support.Logger;
import freenet.support.api.Bucket;
import freenet.support.io.TempBucketFactory;
@@ -37,7 +48,7 @@
* @author Julien Cornuwel ([EMAIL PROTECTED])
*
*/
-public class IdentityInserter implements Runnable {
+public class IdentityInserter implements Runnable, ClientCallback {
private static final int THREAD_PERIOD = 30 * 60 * 1000;
@@ -51,6 +62,8 @@
private volatile boolean isRunning;
private Thread mThread;
+ private final ArrayList<ClientPutter> mInserts = new
ArrayList<ClientPutter>(10); /* Just assume that there are 10 identities */
+
/**
* Creates an IdentityInserter.
*
@@ -71,6 +84,7 @@
*/
public void run() {
mThread = Thread.currentThread();
+ Logger.debug(this, "Identity inserter thread started.");
try {
Thread.sleep((long) (3*60*1000 * (0.5f +
Math.random()))); // Let the node start up
@@ -89,9 +103,6 @@
try {
Logger.debug(this, "Starting
insert of "+identity.getNickName() + " (" + identity.getInsertURI().toString()
+ ")");
insert(identity);
- // We set the date now, so if
the identity is modified during the insert, we'll insert it again next time
- identity.setLastInsert(new
Date());
- db.store(identity);
} catch (Exception e) {
Logger.error(this, "Identity
insert failed: "+e.getMessage(), e);
}
@@ -105,10 +116,22 @@
catch (InterruptedException e)
{
mThread.interrupt();
+ Logger.debug(this, "Identity inserter thread
interrupted.");
}
}
+
+ cancelInserts();
+ Logger.debug(this, "Identity inserter thread finished.");
}
+ private synchronized void cancelInserts() {
+ Iterator<ClientPutter> i = mInserts.iterator();
+ int icounter = 0;
+ Logger.debug(this, "Trying to stop all inserts");
+ while (i.hasNext()) { i.next().cancel(); ++icounter; }
+ Logger.debug(this, "Stopped " + icounter + " current inserts");
+ }
+
/**
* Stops the IdentityInserter thread.
*/
@@ -145,44 +168,98 @@
* @throws InvalidParameterException
* @throws InsertException
*/
- private void insert(OwnIdentity identity) throws
TransformerConfigurationException, FileNotFoundException,
ParserConfigurationException, TransformerException, IOException,
Db4oIOException, DatabaseClosedException, InvalidParameterException,
InsertException {
+ private synchronized void insert(OwnIdentity identity) throws
TransformerConfigurationException, FileNotFoundException,
ParserConfigurationException, TransformerException, IOException,
Db4oIOException, DatabaseClosedException, InvalidParameterException,
InsertException {
/* FIXME: Where is the synchronization? */
/* TODO: after the WoT has become large enough, calculate the
average size of identity.xml and either modify the constant or even calculate
dynamically */
Bucket tempB = tBF.makeBucket(8 * 1024);
OutputStream os = tempB.getOutputStream();
- FreenetURI iURI;
+
try {
// Create XML file to insert
identity.exportToXML(db, os);
- os.close();
+ os.close(); os = null;
tempB.setReadOnly();
// Prepare the insert
ClientMetadata cmd = new ClientMetadata("text/xml");
InsertBlock ib = new
InsertBlock(tempB,cmd,identity.getInsertURI());
+ InsertContext ictx = client.getInsertContext(true);
+
+ /* FIXME: are these parameters correct? */
+ ClientPutter pu = client.insert(ib, false,
"identity.xml", false, ictx, this);
+
pu.setPriorityClass(RequestStarter.UPDATE_PRIORITY_CLASS);
+ mInserts.add(pu);
+ tempB = null;
- // Logging
- Logger.debug(this, "Started insert of identity '" +
identity.getNickName() + "'");
-
- /* FIXME: use nonblocking insert */
- // Blocking Insert
- iURI = client.insert(ib, false, "identity.xml");
-
- identity.setEdition(iURI.getSuggestedEdition());
+ // We set the date now, so if the identity is modified
during the insert, we'll insert it again next time
identity.setLastInsert(new Date());
- db.store(identity);
- db.commit();
-
- // Logging
- Logger.debug(this, "Successful insert of identity '" +
identity.getNickName() + "'");
+ Logger.debug(this, "Started insert of identity '" +
identity.getNickName() + "'");
}
catch(Exception e) {
Logger.error(this,"Error during insert of identity '" +
identity.getNickName() + "'", e);
}
finally {
- tempB.free();
+ if(tempB != null)
+ tempB.free();
+ if(os != null)
+ os.close();
}
}
+
+ // Only called by inserts
+ public synchronized void onSuccess(BaseClientPutter state)
+ {
+ try {
+ OwnIdentity identity = OwnIdentity.getByURI(db,
state.getURI());
+
identity.setEdition(state.getURI().getSuggestedEdition());
+
+ db.store(identity);
+ db.commit();
+ Logger.debug(this, "Successful insert of identity '" +
identity.getNickName() + "'");
+ } catch(Exception e) { Logger.error(this, "Error", e); }
+ state.cancel(); /* FIXME: is this necessary */
+ mInserts.remove(state);
+ }
+
+ // Only called by inserts
+ public synchronized void onFailure(InsertException e, BaseClientPutter
state)
+ {
+ try {
+ OwnIdentity identity = OwnIdentity.getByURI(db,
state.getURI());
+
+ Logger.error(this, "Error during insert of identity '"
+ identity.getNickName() + "'", e);
+ } catch(Exception ex) { Logger.error(this, "Error", e); }
+ state.cancel(); /* FIXME: is this necessary */
+ mInserts.remove(state);
+ }
+
+ /* Not needed functions from the ClientCallback inteface */
+
+ public void onFailure(FetchException e, ClientGetter state) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void onFetchable(BaseClientPutter state) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void onGeneratedURI(FreenetURI uri, BaseClientPutter state) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void onMajorProgress() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void onSuccess(FetchResult result, ClientGetter state) {
+ // TODO Auto-generated method stub
+
+ }
}
+
Modified: trunk/plugins/WoT/WoT.java
===================================================================
--- trunk/plugins/WoT/WoT.java 2008-11-16 14:34:36 UTC (rev 23644)
+++ trunk/plugins/WoT/WoT.java 2008-11-16 15:53:42 UTC (rev 23645)
@@ -164,6 +164,7 @@
}
public void terminate() {
+ Logger.debug(this, "WoT plugin terminating ...");
if(inserter != null) inserter.stop();
if(introductionServer != null) introductionServer.terminate();
if(introductionClient != null) introductionClient.terminate();
@@ -172,6 +173,7 @@
db.commit();
db.close();
}
+ Logger.debug(this, "WoT plugin terminated.");
}
public String handleHTTPGet(HTTPRequest request) throws
PluginHTTPException {
Modified: trunk/plugins/WoT/introduction/IntroductionClient.java
===================================================================
--- trunk/plugins/WoT/introduction/IntroductionClient.java 2008-11-16
14:34:36 UTC (rev 23644)
+++ trunk/plugins/WoT/introduction/IntroductionClient.java 2008-11-16
15:53:42 UTC (rev 23645)
@@ -127,6 +127,8 @@
IntroductionPuzzle.deleteExpiredPuzzles(db);
downloadPuzzles();
+ Logger.debug(this, "Introduction client loop
finished.");
+
try {
Thread.sleep((long) (THREAD_PERIOD * (0.5f +
Math.random())));
}
@@ -135,14 +137,13 @@
mThread.interrupt();
Logger.debug(this, "Introduction client loop
interrupted.");
}
- Logger.debug(this, "Introduction client loop
finished.");
}
cancelRequests();
Logger.debug(this, "Introduction client thread finished.");
}
- public synchronized void terminate() {
+ public void terminate() {
Logger.debug(this, "Stopping the introduction client...");
isRunning = false;
mThread.interrupt();
@@ -201,6 +202,7 @@
ClientPutter pu = mClient.insert(ib, false, null,
false, ictx, this);
pu.setPriorityClass(RequestStarter.UPDATE_PRIORITY_CLASS);
mInserts.add(pu);
+ tempB = null;
Logger.debug(this, "Started to insert puzzle solution
of " + solver.getNickName() + " at " + solutionURI);
@@ -209,7 +211,8 @@
db.commit();
}
finally {
- tempB.free();
+ if(tempB != null)
+ tempB.free();
if(os != null)
os.close();
}
@@ -326,11 +329,9 @@
Logger.error(this, "Parsing failed for "+
state.getURI(), e);
}
}
-
- /* Not needed functions from the ClientCallback inteface */
-
+
// Only called by inserts
- public void onSuccess(BaseClientPutter state)
+ public synchronized void onSuccess(BaseClientPutter state)
{
Logger.debug(this, "Successful insert of puzzle solution at " +
state.getURI());
state.cancel(); /* FIXME: is this necessary */
@@ -338,7 +339,14 @@
}
// Only called by inserts
- public void onFailure(InsertException e, BaseClientPutter state) {}
+ public synchronized void onFailure(InsertException e, BaseClientPutter
state)
+ {
+ Logger.debug(this, "Insert of puzzle solution failed for " +
state.getURI(), e);
+ state.cancel(); /* FIXME: is this necessary */
+ mInserts.remove(state);
+ }
+
+ /* Not needed functions from the ClientCallback inteface */
// Only called by inserts
public void onFetchable(BaseClientPutter state) {}
Modified: trunk/plugins/WoT/introduction/IntroductionPuzzle.java
===================================================================
--- trunk/plugins/WoT/introduction/IntroductionPuzzle.java 2008-11-16
14:34:36 UTC (rev 23644)
+++ trunk/plugins/WoT/introduction/IntroductionPuzzle.java 2008-11-16
15:53:42 UTC (rev 23645)
@@ -161,7 +161,7 @@
* @return
* @throws ParseException
*/
- public static IntroductionPuzzle getBySolutionURI(ObjectContainer db,
FreenetURI uri) throws ParseException {
+ public static IntroductionPuzzle getByURI(ObjectContainer db,
FreenetURI uri) throws ParseException {
UUID id = UUID.fromString(uri.getDocName().split("|")[3]);
Query q = db.query();
Modified: trunk/plugins/WoT/introduction/IntroductionServer.java
===================================================================
--- trunk/plugins/WoT/introduction/IntroductionServer.java 2008-11-16
14:34:36 UTC (rev 23644)
+++ trunk/plugins/WoT/introduction/IntroductionServer.java 2008-11-16
15:53:42 UTC (rev 23645)
@@ -29,10 +29,12 @@
import freenet.client.FetchResult;
import freenet.client.HighLevelSimpleClient;
import freenet.client.InsertBlock;
+import freenet.client.InsertContext;
import freenet.client.InsertException;
import freenet.client.async.BaseClientPutter;
import freenet.client.async.ClientCallback;
import freenet.client.async.ClientGetter;
+import freenet.client.async.ClientPutter;
import freenet.keys.FreenetURI;
import freenet.node.RequestStarter;
import freenet.support.Logger;
@@ -70,6 +72,9 @@
private final IntroductionPuzzleFactory[] mPuzzleFactories = new
IntroductionPuzzleFactory[] { new CaptchaFactory1() };
private final ArrayList<ClientGetter> mRequests = new
ArrayList<ClientGetter>(PUZZLE_COUNT * 5); /* Just assume that there are 5
identities */
+
+ private final ArrayList<ClientPutter> mInserts = new
ArrayList<ClientPutter>(PUZZLE_COUNT * 5); /* Just assume that there are 5
identities */
+
/**
* Creates an IntroductionServer
@@ -122,6 +127,7 @@
}
}
db.commit();
+ Logger.debug(this, "Introduction server loop
finished.");
try {
Thread.sleep((long) (THREAD_PERIOD * (0.5f +
Math.random())));
@@ -131,14 +137,13 @@
mThread.interrupt();
Logger.debug(this, "Introduction server loop
interrupted.");
}
- Logger.debug(this, "Introduction server loop
finished.");
}
cancelRequests();
Logger.debug(this, "Introduction server thread finished.");
}
- public synchronized void terminate() {
+ public void terminate() {
Logger.debug(this, "Stopping the introduction server...");
isRunning = false;
mThread.interrupt();
@@ -153,11 +158,15 @@
}
private synchronized void cancelRequests() {
- Iterator<ClientGetter> i = mRequests.iterator();
- int counter = 0;
- Logger.debug(this, "Trying to stop all requests");
- while (i.hasNext()) { i.next().cancel(); ++counter; }
- Logger.debug(this, "Stopped " + counter + " current requests");
+ Iterator<ClientGetter> r = mRequests.iterator();
+ Iterator<ClientPutter> i = mInserts.iterator();
+ int rcounter = 0;
+ int icounter = 0;
+ Logger.debug(this, "Trying to stop all requests & inserts");
+ while (r.hasNext()) { r.next().cancel(); ++rcounter; }
+ while (i.hasNext()) { i.next().cancel(); ++icounter; }
+ Logger.debug(this, "Stopped " + rcounter + " current requests");
+ Logger.debug(this, "Stopped " + icounter + " current inserts");
}
private synchronized void downloadSolutions(OwnIdentity identity)
throws FetchException {
@@ -219,15 +228,17 @@
ClientMetadata cmd = new
ClientMetadata("text/xml");
InsertBlock ib = new InsertBlock(tempB,
cmd, p.getInsertURI());
+ InsertContext ictx =
mClient.getInsertContext(true);
+
+ /* FIXME: are these parameters correct?
*/
+ ClientPutter pu = mClient.insert(ib,
false, null, false, ictx, this);
+
pu.setPriorityClass(RequestStarter.UPDATE_PRIORITY_CLASS);
+ mInserts.add(pu);
+ tempB = null;
- Logger.debug(this, "Started insert
puzzle from " + identity.getNickName());
-
- /* FIXME: use nonblocking insert maybe
*/
- mClient.insert(ib, false, null);
-
db.store(p);
db.commit();
- Logger.debug(this, "Successful insert
of puzzle from " + identity.getNickName() + ": " + p.getRequestURI());
+ Logger.debug(this, "Started insert of
puzzle from " + identity.getNickName());
}
catch(InsertException e) {
if(e.errorCodes.getFirstCode() ==
InsertException.COLLISION)
@@ -241,7 +252,8 @@
while(retryWithNewIndex);
}
finally {
- tempB.free();
+ if(tempB != null)
+ tempB.free();
if(os != null)
os.close();
}
@@ -266,7 +278,7 @@
try {
db.commit();
- IntroductionPuzzle p =
IntroductionPuzzle.getBySolutionURI(db, state.getURI());
+ IntroductionPuzzle p = IntroductionPuzzle.getByURI(db,
state.getURI());
OwnIdentity puzzleOwner = (OwnIdentity)p.getInserter();
Identity newIdentity =
Identity.importIntroductionFromXML(db, mIdentityFetcher,
result.asBucket().getInputStream());
puzzleOwner.setTrust(db, newIdentity, (byte)0, null);
/* FIXME: is 0 the proper trust for newly imported identities? */
@@ -281,14 +293,30 @@
}
}
- /* Not needed functions from the ClientCallback inteface */
-
// Only called by inserts
- public void onSuccess(BaseClientPutter state) {}
+ public synchronized void onSuccess(BaseClientPutter state)
+ {
+ try {
+ IntroductionPuzzle p = IntroductionPuzzle.getByURI(db,
state.getURI());
+ Logger.debug(this, "Successful insert of puzzle from "
+ p.getInserter().getNickName() + ": " + p.getRequestURI());
+ } catch(Exception e) { Logger.error(this, "Error", e); }
+ state.cancel(); /* FIXME: is this necessary */
+ mInserts.remove(state);
+ }
// Only called by inserts
- public void onFailure(InsertException e, BaseClientPutter state) {}
+ public synchronized void onFailure(InsertException e, BaseClientPutter
state)
+ {
+ try {
+ IntroductionPuzzle p = IntroductionPuzzle.getByURI(db,
state.getURI());
+ Logger.debug(this, "Insert of puzzle failed from " +
p.getInserter().getNickName() + ": " + p.getRequestURI(), e);
+ } catch(Exception ex) { Logger.error(this, "Error", e); }
+ state.cancel(); /* FIXME: is this necessary */
+ mInserts.remove(state);
+ }
+ /* Not needed functions from the ClientCallback inteface */
+
// Only called by inserts
public void onFetchable(BaseClientPutter state) {}
_______________________________________________
cvs mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs