PureMVC Architects Lounge

PureMVC Manifold => MultiCore Version => Topic started by: riafan on June 11, 2008, 01:20:33



Title: Pipes Utility - Disconnecting Pipes
Post by: riafan on June 11, 2008, 01:20:33
I refactored the MortgageApp to use the pipes utility.  I like the approach the Pipes utility takes - build the module-app app-module integration on top of the exisiting modules (i.e. add a junction  mediator to your exisiting module and ensure your module implements IPipeAware).

Cool stuff Cliff.

I did run into a question however.  I'm finding the need to disconnect individual 'pipes' from a TeeSplit or TeeMerge - not simply 'all' pipes. 

For example, my 'shell app' has an outbound (TeeSplit) and inbound (TeeMerge) pipe.  Dynamically loaded modules create pipes and connect to the latter 'shell' pipes.

When it comes time to unload a dynamically loaded module, I currently don't have a way to remove to the connection to the app's TeeSplit / TeeMerge without disconnecting all of the other modules' pipes as well. 

I simply subclassed TeeSplit and added function to disconnect the passed fitting. 

:
public function disconnectFitting(output:IPipeFitting):IPipeFitting
Doing so solved my problem.

*If* I'm not missing something, it might be worthwhile to add the latter function to TeeSplit.

Thanks


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: puremvc on June 13, 2008, 07:07:22
Excellent solution to the problem! I agree and will probably integrate this into the utility class as you suggest.

Glad to hear you've had a positive experience with it in your own app. And thanks for taking the time to report your findings and help improve the project.

-=Cliff>



Title: Re: Pipes Utility - Disconnecting Pipes
Post by: riafan on June 13, 2008, 08:03:07
No problem.  I've posted an architectural diagram over at http://joshuaostrom.com (http://joshuaostrom.com) to help anyone working with the Pipes Utility.

Josh


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: sectore on June 21, 2008, 12:38:21
Run into the same issue.

With a basic example using PureMVC MultiCore AS3, Pipes Utility and modules (http://www.websector.de/blog/2008/06/21/a-basic-puremvc-multicore-as3-example-using-pipes-utility-and-modules/) posted on my blog  I tried to figure out, what a good way to disconnect pipes connecting by a shell and a module (which is loaded by shell) could be.

So before unloading the module the shell disconnect the SHELL_TO_MODULE_PIPE (TeeSplit) and the module disconnects the MODULE_TO_SHELL_PIPE (Pipe). When the module is loaded again, these pipes will be connected again. That works fine.

However, is there anything to do to remove the other (unused) fittings of pipes which are used by module and shell together before the module is unloaded?

Feel free to check out the code of the example mentioned above (http://www.websector.de/blog/2008/06/21/a-basic-puremvc-multicore-as3-example-using-pipes-utility-and-modules/), because "real" code is worth a thousand words ;) .

Any feedback are welcome!

-sectore


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: puremvc on June 21, 2008, 01:24:41
is there anything to do to remove the other (unused) fittings of pipes which are used by module and shell together before the module is unloaded?

If you are unloading the module from code inside the shell, you presumably have a reference to the shell-end of the pipeline. What you could do is de-construct the pipeline by repeatedly calling 'disconnect' on the pipe fitting returned by the previous disconnect.

So if you had an output pipeline going from the shell into the module like:

:
Pipe + Filter + Queue + Pipe
And you have a reference to the first Pipe, then calling 'disconnect' on the Pipe will disconnect and return the Filter, which is still connected to the rest of the pipeline.

Now you have a reference to:

:
Filter + Queue + Pipe
calling 'disconnect' on the Filter will yield:

:
Queue + Pipe
and finally, calling 'disconnect' on the Queue will yield:

:
Pipe
Of course if you have a complex set of pipeworks you're going to need a smarter plumber. :)

However, I believe that removing the references to both ends of the pipe will suffice for the entire pipeline to be GC'd because there are no outside references to these objects.
The pipeline essentially becomes an 'unreachable island' in memory.

In addition to reference counting, the Flash Player GC also implements a two-pass 'mark and sweep' algorithm. First, beginning with the root object, it traverses all reachable objects and marks them. Then the sweep pass destroys any objects not marked and reclaims the memory.

-=Cliff>


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: sectore on June 22, 2008, 01:21:39
Cliff, thanks for the detailed information I needed!

However, I believe that removing the references to both ends of the pipe will suffice for the entire pipeline to be GC'd because there are no outside references to these objects.

Ok, that's what I did. I removed only references of both ends of each pipe:

SHELL_TO_MODULE_PIPE:
- Shell disconnects its end (TeeSplit)
:
var shellOutPipe: TeeSplit = junction.retrievePipe( PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE ) as TeeSplit;
shellOutPipe.disconnect();

MODULE_TO_SHELL_PIPE:
- Module disconnects its end (Pipe)
:
var moduleOutPipe: Pipe = junction.retrievePipe( PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE ) as Pipe;
moduleOutPipe.disconnect();

Cliff, thanks for sharing the powerful Pipes Utility!

-Jens




Title: Re: Pipes Utility - Disconnecting Pipes
Post by: puremvc on June 22, 2008, 05:04:09
Actually if you're just wanting to remove the entire pipeline, you can just do junction.removePipe(pipeName) on both ends.

The way you've done it, the junctions still retain a referenct to the pipe fittings on the ends, and only the middle goes away.

-=Cliff> 


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: sectore on June 22, 2008, 09:09:37
Cliff, thanks for the tip!

I refactored the source using
:
junction.removePipe( PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE );
junction.removePipe( PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE );
to remove both unneeded pipes.

Last question: When a pipe is removed as you described, is there a need to remove any PipeListener as well?

-Jens



Title: Re: Pipes Utility - Disconnecting Pipes
Post by: puremvc on June 22, 2008, 11:44:57
No, because the PipeListener has a reference to a reachable object, but not the other way around. It's the last pipe fitting on the pipeline and nothing has a reference to it, it just knows who to notify when a message comes down the pipeline.

-=Cliff>


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: ramanuja on August 01, 2008, 07:59:21
Hi,

With reference to post by rifian (http://forums.puremvc.org/index.php?topic=508.msg2165#msg2165), I have run into the same problem.

I have build a sample app which uses pipes and dynamic loading/unloading of modules. In the ShellJunctionMediator, I have the following code:
:
override public function onRegister():void {

// The SHELL_TO_MODULE_PIPE pipe from the shell to all modules.
junction.registerPipe(PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE, Junction.OUTPUT, new TeeSplit());

// The MODULE_TO_SHELL_PIPE pipe to the shell from all modules.
junction.registerPipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE, Junction.INPUT, new TeeMerge());

// Add a pipe listener for incoming messages to the shell.
junction.addPipeListener(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE, this, handlePipeMessage);

}
...
...
override public function handleNotification(note:INotification):void {

switch (note.getName()) {

case ApplicationFacade.MODULE_ADDED:
// Connect module passed in the notification body to shell.

// Connect a pipe from module to shell. This pipe is output pipe for module and tee merge for shell.
var module:IPipeAwareModule = note.getBody() as IPipeAwareModule;
var moduleToShell:Pipe = new Pipe();
module.acceptOutputPipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE, moduleToShell);
var shellIn:TeeMerge = junction.retrievePipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE) as TeeMerge;
shellIn.connectInput(moduleToShell);

// Connect a pipe from shell to module. This pipe is tee split for shell and input pipe for module.
var shellToModule:Pipe = new Pipe();
module.acceptInputPipe(PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE, shellToModule);
var shellOut:TeeSplit = junction.retrievePipe(PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE) as TeeSplit;
shellOut.connect(shellToModule);
break;

}
}
...
...
override public function handlePipeMessage(message:IPipeMessage):void {

switch (message.getType()) {

case PipeAwareModuleConstants.MODULE_DISPOSAL_MESSAGE:
// Call the dispose method of the module.

// HOW DO I REMOVE PIPES FROM THE SHELL TO THIS MODULE HERE??

var module:IPipeAwareModule = message.getBody() as IPipeAwareModule;
module.dispose();
break;
}

}

// HOW DO I REMOVE PIPES FROM THE SHELL TO THIS MODULE HERE??

I am doing, sendNotification(ApplicationFacade.MODULE_ADDED); each time I want to add a new module.

Now when it is time to remove module 'x', how do I remove the pipes attached to module 'x' in the TeeMerge and TeeSplit? I do not want to do:
:
junction.removePipe( PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE );
junction.removePipe( PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE );
because it will remove the pipes with other required modules as well.

rifian said subclassing TeeSplit and adding
:
public function disconnectFitting(output:IPipeFitting):IPipeFittinghelped.

But, how do I get a reference of the output:IPipeFitting that I must I pass to the above method?

Please help!!  :'(

Thanks,
Ramanuja


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: riafan on August 01, 2008, 08:51:21
The approach I took was to have the module 'cache' the fittings when connecting them.

:
module.cacheFitting(moduleToApp,appIn);
:
public function cacheFitting(localFitting:IPipeFitting,remoteFitting:IPipeFitting):void
{
cachedFittings.push({local:localFitting,remote:remoteFitting});
}

Then, when it comes time to unload a loaded module, I simply 'cleanup'

:
public function cleanup():void
{
while(cachedFittings.length > 0)
{
var localFitting:IPipeFitting = cachedFittings[cachedFittings.length-1].local;
var remoteFitting:IPipeFitting = cachedFittings[cachedFittings.length-1].remote;

if(remoteFitting is DynamicTeeSplit)
   (remoteFitting as DynamicTeeSplit).disconnectFitting(localFitting);

localFitting.disconnect();
cachedFittings.pop();
       }
}

Hope that helps!!!


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: ramanuja on August 01, 2008, 11:42:26
Hi,

I like your implementation a LOT riafan. Its very neat.

I have a couple of doubts. I am sure you can solve them for me  :)

1. cachedFittings is a private var Array in the module right? So every module, has an array called cachedFittings that holds {local:localFitting,remote:remoteFitting}. Am I right here?

2. I have doubt with module.cacheFitting() method you mentioned. Should it not be
:
module.cacheFitting(appToModule,appOut); // It was ...(moduleToApp,appIn) before?

3. The DynamicTeeSplit which extends TeeSplit, has a method:
:
public function disconnectFitting(output:IPipeFitting):IPipeFittingIs this implementation correct?
:
public function disconnectFitting(output:IPipeFitting):IPipeFitting
{
for (var i:int=0;i<outputs.length;i++)
{
if (outputs[i] == output) {
// Remove the ith IPipeFitting.
outputs.splice(i, 1);
}
}
return output;
}

Does garbage collection happen for the ith element that is discarded above?


3. Is there no need for a DynamicTeeMerge? This question may be stupid but I just want to confirm. The moduleToApp pipe is connected to the TeeMerge of the app. I saw the implementation of TeeMerge.connectInput() method. The app maintains no reference to individual pipes that are merged right? How many ever modules may connect to the TeeMerge of the app. When unloading the module, it is sufficient to just execute the following?
:
// This is a method in the module's junction mediator.
override public function onRemove():void {
// Remove both pipes (shell -> module && module -> shell )
junction.removePipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE);
junction.removePipe(PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE);
}
junction.removePipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE); will remove the moduleToApp pipe completely? Will it be garbage collected?

I have asked a lot of questions   :-X
KEENLY awaiting your response.

Thanks,
Ramanuja.


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: newtriks on August 04, 2008, 03:33:10
Hi all,

I have been spending some time trying to delve into Garbage Collection for effective loading and unloading of modules within a MultiCore application and have achieved some good results.  I have made a blog post regarding my results and also build a demo application to help people further grasp techniques I have used:

http://www.nutrixinteractive.com/blog/?p=132 (http://www.nutrixinteractive.com/blog/?p=132)

Cheers,

Simon

http://newtriks.com (http://newtriks.com)


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: ramanuja on August 04, 2008, 09:39:01
Hi,

Great learning for me from Simon's post about GC!

Is there a way to do this without the timer? I want the removeChild() to be executed as soon as the core is removed.

Lets say we want to remove a core CORE_NAME,

:
while (Facade.hasCore(CORE_NAME) != null) {
    // infinite loop
}

// Now remove child
app.removeChild(...);

Thanks,
Ramanuja.


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: ramanuja on August 04, 2008, 09:40:54
Cliff,

1. Does it make sense to have a Facade.hasCore() mehod to support the above post?
(if its correct  :-\)

2. In my ModuleJunctionMediator's onRemove() method:
:
override public function onRemove():void {
// Remove both pipes (shell -> module && module -> shell )
junction.sendMessage(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE,
new Message(PipeAwareModuleConstants.MODULE_DISPOSED_MESSAGE, null, 
        PipeAwareModuleConstants.MY_MODULE));
junction.removePipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE);
junction.removePipe(PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE);
}
Will the message sent above reach the shell junction? This way, the hasCore() idea is not required. I feel the infinite loop is not a good design. Waiting to get your views on this.

Thanks,
Ramanuja.


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: puremvc on August 07, 2008, 05:20:29
Yes, assuming the pipe to the shell was working before the mediator was removed, it should still work afterwards. The junction still exists, you've merely removed the mediator from the View in the module, so it can no longer be notified.

-=Cliff>


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: puremvc on August 07, 2008, 05:52:28
Also, you don't have to break the pipeline apart and dispose of each fitting separately for them to be GC'd.

Due to the way Flash does garbage collection (reference counting + mark & sweep), you can simply remove the pipes leading to or from the module in question, do a removeCore on the module's facade, then unload the module. QED.

In the simplest of bidirectional cases, the ShellJunctionMediator has an output pipe leading to the module and an input pipe coming from the module.

So. inside the ShellJunctionMediator, remove both of those pipes. Now you have a module, with pipes sticking out of it connected to nothing, floating in memory with no outside references from the main app. Call facade.removeCore passing the multitonKey of the module. Then unload the module. Then call for GC.

-=Cliff>


Title: Re: Pipes Utility - Disconnecting Pipes
Post by: puremvc on October 02, 2008, 05:50:54
@riafan: http://forums.puremvc.org/index.php?topic=508.msg2165#msg2165

I added the disconnectFitting method as you described, and added a unit test. The latest version of pipes is 1.1

-=Cliff>