On Tue, Jul 7, 2009 at 10:08 PM, Matthew
Toseland<toad at amphibian.dyndns.org> wrote:
> On Tuesday 07 July 2009 20:41:54 sashee wrote:
>> Maybe I don't see something, but I think it is much more simpler. Here it is:
>>
>> When the processing of RequestElement starts, the ClientRequest object
>> is already activated, because FCPClient:305 activates all requests,
>> and puts to the v List, and those object are the very same objects
>> RequestElement works with. So they are initialized, but maybe the
>> Fetch(Insert)Context isn't. So activate it. And also the EventProducer
>> if not activated. As the constructor has the ObjectContainer object,
>> it can activate. As I see this is used at ClientGet:785. invoked from
>> RequestElement:122 , and it seems to be working.
>
> Yes. But these objects may become deactivated shortly after the constructor 
> ends.

Why can they deactivated? They are actively fetching a file, so they
are needed. Where are they deactivated?
>>
>> The only problem seems to be that these listeners shouldn't be
>> persisted, they aren't supposed to survive a restart. So I think I
>> should create a mechanism for transient eventlisteners.
>
> Which is pretty much what I was saying. You can't just add a listener to each 
> request because it may be deactivated. But if you add it at e.g. the 
> FCPClient level, you can get a callback while it is active.
>>
>> What you think about it?
>>
>> sashee
>>
>> On Tue, Jul 7, 2009 at 7:56 PM, Matthew
>> Toseland<toad at amphibian.dyndns.org> wrote:
>> > On Tuesday 07 July 2009 18:50:58 Matthew Toseland wrote:
>> >> 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.
>> >>
>> > Also, you should not store the ObjectContainer, and should not access the 
>> > database except on the database thread (i.e. when an ObjectContainer has 
>> > been passed in ultimately from a DBJob).
>> >
>> > _______________________________________________
>> > Devl mailing list
>> > Devl at freenetproject.org
>> > http://emu.freenetproject.org/cgi-bin/mailman/listinfo/devl
>> >
>> _______________________________________________
>> Devl mailing list
>> Devl at freenetproject.org
>> http://emu.freenetproject.org/cgi-bin/mailman/listinfo/devl
>>
>>
>
>
>

Reply via email to