On Tuesday 07 July 2009 21:10:19 sashee wrote: > On Tue, Jul 7, 2009 at 10:08 PM, Matthew > Toseland<[email protected]> 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?
They are deactivated to save memory. We have lots of files to fetch and we can't afford to keep everything in RAM. > >> > >> 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<[email protected]> 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 > >> > [email protected] > >> > http://emu.freenetproject.org/cgi-bin/mailman/listinfo/devl > >> > > >> _______________________________________________ > >> Devl mailing list > >> [email protected] > >> http://emu.freenetproject.org/cgi-bin/mailman/listinfo/devl > >> > >> > > > > > > > >
signature.asc
Description: This is a digitally signed message part.
_______________________________________________ Devl mailing list [email protected] http://emu.freenetproject.org/cgi-bin/mailman/listinfo/devl
