On Tuesday 07 July 2009 18:26:40 Matthew Toseland wrote:
> public void addEventListener(ClientEventListener cel) {
> + if(listeners==null){
> + //Don't know how it can happen, but it did, and checking for
> null isn't going to hurt anything
> + listeners=new Vector<ClientEventListener>();
> + }
> if(cel != null)
> listeners.addElement(cel);
> else
> throw new IllegalArgumentException("Adding a null listener!");
> }
>
> It can't happen for transient requests. For persistent requests, a
> persistence-related bug in the code might well cause it to happen however. :(
>
Okay, now I see what is going on ...
+ public RequestElement(ClientRequest clientRequest, int[] columns,
String path, ObjectContainer container, boolean advancedModeEnabled, String[]
priorityClasses, boolean isUpload, ToadletContext ctx) {
...
+ if (clientRequest instanceof ClientGet) {
+ if (((ClientGet)
clientRequest).getFetchContext().eventProducer != null) ((ClientGet)
clientRequest).getFetchContext().eventProducer.addEventListener(progressListener);
+ } else if (clientRequest instanceof ClientPutBase) {
+ if (((ClientPutBase)
clientRequest).getInsertContext().eventProducer != null) ((ClientPutBase)
clientRequest).getInsertContext().eventProducer.addEventListener(progressListener);
+ } else {
+ System.err.println("Dont know this type! type:" +
clientRequest.getClass());
+ }
+
clientRequest.getClient().addRequestCompletionCallback(progressListener);
+ }
Anything on the download/upload page is a persistent request. A persistent
request is either persistence=reboot or persistence=forever, but the latter is
far more common. These requests are *stored in a database*, and are not always
in memory. Using them as variables will cause them to be pinned in memory but
will not ensure they stay "activated" i.e. that all their fields are loaded and
non-null. The only safe way to access them is to schedule a job on the database
thread (the DBJobRunner, aka NodeClientCore). Hence, the SimpleEventProducer
may well be null, and even if it isn't, it may not be activated, meaning the
listeners array may be null.
Hence subscribing to the SimpleEventProducer and listening for events is not
going to be sufficient. You need to implement some sort of global hook, so that
when an event is generated against a request in the global queue (only the
global queue is shown on the downloads/uploads pages), you get a notification,
at that point, while the request is still active.
What you need to do is as follows:
- FCPServer.globalRebootClient is the half of the global queue that is
persistence=reboot, that is, the part that isn't persisted to the database. You
can ignore it for all practical purposes, but you should really deal with it
when you get around to it.
- FCPServer.globalForeverClient is the half of the global queue that is
persistence=forever, and in practice has almost all global requests (requests
or inserts shown on the downloads/uploads pages). It is never deactivated.
- This is an FCPClient.
- You need to create a callback method and a registry of listeners on FCPClient
that gets fed every FCP event, at the time it is created, along with the
ClientRequest which created it. This happens in ClientGet.receive,
ClientPutBase.receive, and probably that's about it; check the call hierarchy
for the constructors for e.g. SimpleProgressMessage if you are concerned. This
always happens on the database thread, or at least, if it's not on the database
thread, it schedules a job on the database thread to send the message (e.g. in
ClientPutBase.trySendProgressMessage). So call the callback at that point.
- The callback should go to some sort of manager object, which determines which
RequestElement(s) want the message. Or you can just register all of them but it
will be slower that way.
- Don't store the pointers, store the UID of the request (this is because we
don't want to pin the request object in memory). This is an long value for a
specific request in the database which doesn't change unless we defrag (which
is an offline operation). You can get it by:
container.ext().getID(<object>).
Please let me know if you need any more information on this! The db4o zip file
contains javadocs, you can get it from db4o.com, we use version 7.4.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 835 bytes
Desc: This is a digitally signed message part.
URL:
<https://emu.freenetproject.org/pipermail/devl/attachments/20090707/3adf2a75/attachment.pgp>