Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Pages: [1]
Print
Author Topic: [DEFUSED] Notifier.facade & Junction.removePipe() doesn't disconnect!  (Read 10718 times)
simon_ustwo
Newbie
*
Posts: 5


View Profile Email
« on: April 06, 2009, 06:23:33 »

Hi, I'm not sure where to report this bug?

I've got the multicore version up and working and have several cores all interacting using the Pipes interaction. The issue is when disconnecting the pipes and I send a message through Pipes. The core I removed gets rebooted because of the Notifier get facade. So there is two main bugs,
  • removeCore doesn't stop the Notifier get facade from rebooting the Facade
  • removePipe doesn't disconnect the Pipe

The first issue; I had assumed that multitonKey would be set to null when you remove a core, so walking down the tree and nulling multitonKey. This should and would prevent any possibility of the core being used again. I've edited my version to do this, so it cleans up after itself.

The second issue; just removing the IPipeFitting from the pipesMap isn't enough, you have to disconnect the pipe. I don't want to have to disconnect the pipes manually as I would have to store a reference to that and that's just duplicating code unnecessary. So I've edited the removePipe to the following --->

:
public function removePipe( name:String ):void
{
        if ( hasPipe(name) )
        {
                var type:String = pipeTypesMap[name];
                var pipesList:Array;
                switch (type) {
                        case INPUT:
                                pipesList = inputPipes;
                                break;                                         
                        case OUTPUT:
                                pipesList = outputPipes;       
                                break;                                 
                }
                var pipe : IPipeFitting;
                for (var i:int=pipesList.length-1;i>=0;--i){
                        if (pipesList[i] == name){
                                pipe = pipesMap[name] as IPipeFitting;
                                pipe.disconnect();

                                pipesList.splice(i, 1);
                        }
                }
                delete pipesMap[name];
                delete pipeTypesMap[name];
        }
}

This has solved my problem and cleaned up any cores that are hanging on!
« Last Edit: April 06, 2009, 04:07:49 by puremvc » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #1 on: April 06, 2009, 03:46:13 »

removeCore doesn't stop the Notifier get facade from rebooting the Facade
Not sure what you mean by this. Facade.removeCore is a STATIC method, and does this:

:
        public static function removeCore( key:String ) : void
        {
            if (instanceMap[ key ] == null) return;
            Model.removeModel( key );
            View.removeView( key );
            Controller.removeController( key );
            delete instanceMap[ key ];
        }

Are you suggesting it should operate differently?

just removing the IPipeFitting from the pipesMap isn't enough, you have to disconnect the pipe.

That pipe, once removed from the pipesList is no longer referenced by anything other than the core you've just cut loose and the pipeline it's connected to. Like having a freshly removed sink with pipes sticking out of it, but not connected to your water / sewer lines sitting in your floor. Once it's no longer connected to anything it can be hauled away. Similarly, once there are no more outside references to the module's facade, the module it is a part of, and the pipes that were connecting that module to the rest of the system, the whole core goes away. Simon Bailey has demonstrated this in his demo on garbage collection. (http://www.nutrixinteractive.com/blog/?p=132)

BUT... GC does operate unpredictably in Flash (http://gskinner.com/blog/archives/2008/04/failure_to_unlo.html).

Conceptually the existing mechanism is sound according to the rules of Flash GC. Even though the Pipe is connected to the Junction in the JunctionMediator in the View of the Module, if no references to the Module or the pipe exist, it is not necessary to disconnect the pipe. They are a cluster of entities that reference each other but are referenced from nowhere else in the VM, and therefore the entire cluster is eligible for GC. Disconnecting the pipe for good measure is not necessary.

Also consider the possibility that the pipe is connected to a filter which is then is connected to the module. Disconnecting the pipe leaves the rest of the apparatus hanging out there, and so would not be effective if it were really necessary to disconnect. You'd need to travel down the pipeline disconnecting each piece. But again, that should never be necessary. Two or more objects referencing each other apart from the rest of the program cannot keep each other from GC eligibility.

I think its extremely likely that during your debugging, you ran into some of the unpredictability of Flash GC and/or were holding references to the module or pieces of it elsewhere.

I've run Simon's GC Demo, loaded a module, sent a message from the shell to the module and from the module back to the shell to show they were plumbed properly. Then after unload, in this case, the memory size was exactly the same before and after.

However, if you run it a number of times, you'll see that the unpredictible behavior of GC crops up. Sometimes it's not the same. Sometimes less, sometimes more. Again check GSkinner's article describing why this is so, and read Simon's article to see what he went through to get this working. It is not possible to force GC to happen. You free things up and the GC gets around to cleaning up (or not) whenever it feels like it.

-=Cliff>
« Last Edit: April 06, 2009, 04:06:23 by puremvc » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #2 on: April 06, 2009, 04:09:26 »

bumped up
Logged
simon_ustwo
Newbie
*
Posts: 5


View Profile Email
« Reply #3 on: April 07, 2009, 01:14:21 »

Hi Cliff,

I think I'm talking about the fine details of how it disconnects and removes the module. I'm using the Facade.removeCore in it's static way like you've shown. The issue I'm having is actually a problem with the Notifier where the pipe would still be connected in some strange way so that it would reload the Facade, but not the actual ModuleFacade the main Facade.

:
protected function get facade():IFacade
{
    if ( multitonKey == null ) throw Error( MULTITON_MSG );
    return Facade.getInstance( multitonKey );
}

If multitonKey is not removed in the removeCore, or after that then this can be still called. This means walking through all Commands, Views and Models to make sure that happens. It might just be the way I'm removing, but essentially I remove commands, mediators, models and then the core at a similar time the external application launches another module. This connects the pipe and that module sends a message, the application calls back and this would some how call this notifier, which in turn reboots the Facade. This wouldn't be bad, but I set up my commands in a initialisation method, which won't get called again because the mulition key has already been set for the Facade and not for the ModuleFacade...

Hope this helps

Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #4 on: April 07, 2009, 08:22:21 »

It is unnecssary to remove all the commands and everything inside the module before removing the core.

Again going back to the analogy of removing a sink from your house plumbing (the sink being the module), you can simply disconnect the water/sewer pipes from the house lines, remove the braces from the wall (any references to the module itself) and then carry the whole thing to the dumpster - QED.

You do not need to take off the faucets, remove the drain stopper sub-assembly, disassemble the U-trap and water pipes that are part of the sink. Once that whole contraption is laying in the floor, you can just haul it off.

So, I understand that the Notifier's implicit facade getter will 'reboot' your facade - (that is return a new Facade instance with the core's multiton key) if called after removeCore. But after you've removed the module, no Notifiers in that module should ever be active again. If there is still activity churning around inside your module stop it before attempting to unload the module.

There are only three things that could cause an INotifier inside your module to access it's facade getter AFTER you've removed it and the references to the pipes connected to it:

1) a Timer call. So stop all timers before unloading.
2) a Service call returning. So wait until all outstanding service calls have returned before unloading.
3) a User interface action. So be sure to remove any outside references to view components owned by the module before unloading.

-=Cliff>
Logged
simon_ustwo
Newbie
*
Posts: 5


View Profile Email
« Reply #5 on: April 07, 2009, 08:33:23 »

Yes agreed, it is down to events happening after the fact. I've created a way to notify my self if this happens and trace an alert whilst in debug mode of the build.

I agree, this isn't a bug now that it's explained, but it's a gotcha that I didn't expect to see.

Thanks for your help
simon
Logged
Pages: [1]
Print