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>

Reply via email to