~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Open Mash Cross Reference
mash/tcl/indiva/imgr/imgr-plan.tcl

Component: ~ [ mash ] ~ [ apps ] ~ [ gsm ] ~ [ lib ] ~ [ otcl ] ~ [ srm ] ~ [ tcl8.3 ] ~ [ tclcl ] ~ [ tk8.3 ] ~ [ tutorials ] ~

  1 # imgr-plan.tcl --
  2 #
  3 #   Planning routines for Indiva Manager.
  4 #
  5 # Copyright (c) 1996-2002 The Regents of the University of California.
  6 # All rights reserved.
  7 #
  8 # Redistribution and use in source and binary forms, with or without
  9 # modification, are permitted provided that the following conditions are met:
 10 #
 11 # A. Redistributions of source code must retain the above copyright notice,
 12 #    this list of conditions and the following disclaimer.
 13 # B. Redistributions in binary form must reproduce the above copyright notice,
 14 #    this list of conditions and the following disclaimer in the documentation
 15 #    and/or other materials provided with the distribution.
 16 # C. Neither the names of the copyright holders nor the names of its
 17 #    contributors may be used to endorse or promote products derived from this
 18 #    software without specific prior written permission.
 19 #
 20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
 21 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 22 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 23 # ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
 24 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 25 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 26 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 27 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 28 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 30 #
 31 # @(#) $Header: /usr/mash/src/repository/mash/mash-1/tcl/indiva/imgr/imgr-plan.tcl,v 1.12 2003/06/10 19:46:38 harlanyu Exp $
 32 
 33 import MashRemoteObject
 34 import IMgrASCP
 35 import IMgrFlow
 36 import IMgrAction
 37 import Zzzz; # import proc sleep
 38 
 39 
 40 #---------------------------------------------------------------------
 41 # Method:
 42 #   IndivaManager create_flow
 43 # Description:
 44 #   Add a flow into the system.  A flow consists of a sequence of 
 45 #   pipelined services that collaborate to achieve the task specified
 46 #   by a user.  The flow starts from a resource called $src_name and 
 47 #   ends at resource called $dest_name  The flow object is returned.
 48 # Arguments:
 49 #   client -- socket for connection to the client.
 50 #   src_name, dest_name -- name of the source and destination.
 51 #   arguments -- Additional options to pass to the services created 
 52 #     by the flow.
 53 # Side Effects:
 54 #   Services may be launched.  Servents are created on the services. 
 55 #   Edges involved in the flow are marked as busy.
 56 #---------------------------------------------------------------------
 57 IndivaManager private create_flow { client src_name dest_name {arguments ""}} {
 58     # Create a new flow.
 59     set flow [new IMgrFlow $src_name $dest_name $client]
 60 
 61     MashClock start
 62     # Find a path in the network that the flow flows through.
 63     set path [$self find_path $src_name $dest_name $flow ]
 64     set t [MashClock stop]
 65     MashLog info "find_path $t ms"
 66 
 67     # If the flow has been aborted during path finding, return
 68     # an error.
 69     if {[$flow is_aborted]} {
 70         set reason [$flow why_abort?]
 71         $self delete_flow $flow
 72         return -code error -errorcode $reason -errorinfo $reason
 73     }
 74 
 75     # Go through all the resources along the path and create
 76     # services.
 77     set dest [$self create_services $flow $path $arguments]
 78     set t [MashClock stop]
 79     MashLog info "create_services $t ms"
 80 
 81     # Now mark each edge along the path as busy. 
 82     $self for_each_edge e $path {
 83         $e busy
 84     }
 85 
 86     # It is possible that a new destination is created.  Here, 
 87     # if "create_services" created a new destination, append it 
 88     # to the list.
 89     if {$dest != $dest_name && $dest != {}} {
 90         lappend path $dest
 91     } 
 92 
 93     # Store the path and flow in the last node of the path. 
 94     set last [lindex $path end]
 95     $self instvar mob_graph_
 96     set last_node [$mob_graph_ get_node $last]
 97     if {$last_node != ""} {
 98         $last_node path $path
 99         $last_node flow $flow
100     }
101 
102     # Update the flow, and commit it (marked it as done). 
103     $flow path $path
104     $flow dest [lindex $path end]
105     $flow commit
106 
107     return $flow
108 }
109 
110 
111 
112 #---------------------------------------------------------------------
113 # Method:
114 #   IndivaManager move_flow
115 # Description:
116 #   Given a $flow and a new dest $dest, redirect the flow such that
117 #   it ends at $dest.  Services in the path are shared as much as
118 #   possible.  
119 # Arguments:
120 #   client -- socket for connection to the client.
121 #   flow -- existing flow to be moved.
122 #   dest -- name of the destination.
123 #   arguments -- Additional options to pass to the services created 
124 #     by the flow.
125 # Side Effects:
126 #   Services may be launched.  Servents are created on the services. 
127 #   Edges involved in the flow are marked as busy.  Old service may
128 #   be removed.
129 #---------------------------------------------------------------------
130 IndivaManager public move_flow { client flow dest {arguments ""}} {
131 
132     # We set the cost of every edge along the flow to 0 to promote
133     # sharing.
134     $self instvar mob_graph_
135     set path [$flow path]
136     $self for_each_edge e $path {
137         set cost($e) [$e cost]
138         $e cost 0
139     }
140 
141     # Find a path that flows from the source of the current flow,
142     # to the given destination.  Since find_path may abort the flow,
143     # we do not want to pass in the current flow.  Instead, we use
144     # a temporary flow.
145     set src [lindex $path 0]
146     set tempflow [new IMgrFlow $src $dest $client]
147     set newpath [$self find_path $src $dest $tempflow]
148     delete $tempflow
149 
150     # Compare $newpath with old $path, find the "branching point" of 
151     # the two paths.  Keep all services before the branching point, 
152     # reconfigure the service at branch point and replace all services 
153     # after the branching point.  Here is an example: old path  
154     # A->B->C->D, new path A->B->X->Y.  We keep A->B, reconfig B->C 
155     # to B->X, delete C->D, and add X->Y.
156     set pos 0
157     while {[lindex $path $pos] == [lindex $newpath $pos]} {
158         incr pos
159     }
160     set branchpos [expr $pos-1]
161     set branchpoint [lindex $path $branchpos]
162     set from [lindex $path $pos]
163     set to [lindex $newpath $pos]
164 
165     # ?
166     $flow dest $dest
167 
168     # Redirect the service to end at the new destination.
169     set dest [$self redir_service $flow $branchpoint $from $to]
170 
171     # If a new destination is created, insert it into the new path.
172     if {$dest != {}} {
173         incr pos
174         set newpath [linsert $newpath $pos $dest]
175     }
176 
177     # Remove services from branchpoint+1 to old dest.
178     set from [lindex $path $pos]
179     foreach to [lrange $path [expr $pos+1] end] {
180         $self stop_service $flow $from $to
181         set e [$mob_graph_ get_edge $from $to]
182         $e free
183         set from $to
184     }
185 
186     # Create new services from along the new branch, and mark
187     # the edges along the new branch as busy.
188     set dest [$self create_services $flow [lrange $newpath $pos end] $arguments]
189     $self for_each_edge e [lrange $newpath $branchpos end] {
190         $e busy
191     }
192 
193     # Restore the cost to its original value.
194     $self for_each_edge e [lrange $path 0 $branchpos] {
195         $e cost $cost($e)
196     }
197 
198     # It is possible that a new destination is created.  Here, 
199     # if "create_services" created a new destination, append it 
200     # to the list.
201     if {$dest != {}} {
202         lappend newpath $dest
203     }
204 
205     # Store the path and flow in the last node of the path. 
206     set last [lindex $newpath end]
207     set last_node [$mob_graph_ get_node $last]
208     if {$last_node != ""} {
209         $last_node path $newpath
210         $last_node flow $flow
211     } else {
212         MashLog warn "$proc: no such node $last"
213     }
214     $flow dest [lindex $path end]
215     $flow path $newpath
216 }
217 
218 
219 
220 #---------------------------------------------------------------------
221 # Method:
222 #   IndivaManager split_flow
223 # Description:
224 #   Given a $flow and a new dest $dest, split the flow such that
225 #   it ends at $dest.  Services in the path are shared as much as
226 #   possible.   A new flow is created, and is returned. 
227 # Arguments:
228 #   client -- client that requested the flow to be splitted.
229 #   flow -- the original flow.
230 #   dest -- name of the new destination resource.
231 #   arguments -- additional option to be passed to the services created
232 #---------------------------------------------------------------------
233 IndivaManager private split_flow { client flow dest {arguments ""}} {
234 
235     # We set the cost of every edge along the flow to 0 to promote
236     # sharing when find path.
237     set path [$flow path]
238     $self for_each_edge e $path {
239         set cost($e) [$e cost]
240         $e cost 0
241     }
242 
243     # Find the path in the network from the source of $flow to 
244     # the given destination $dest.
245     set src [lindex $path 0]
246     set new_flow [new IMgrFlow $src $dest $client]
247     set newpath [$self find_path $src $dest $new_flow]
248 
249     # If the flow has been aborted during path finding, return
250     # an error.
251     if {[$new_flow is_aborted]}  {
252         set reason [$new_flow why_abort?]
253         $self delete_flow $new_flow
254         return -code error -errorcode $reason
255     }
256 
257     # Compare $newpath with old $path, find the "branching point" of 
258     # the two paths.  Keep all services before the branching point, 
259     # reconfigure the service at branchpoint and replace all services 
260     # after the branching point.  Here is an example: old path  
261     # A->B->C->D, new path A->B->X->Y.  We keep A->B, copy B->C to 
262     # B->X, and add X->Y.
263 
264     set pos 0
265     while {[lindex $path $pos] == [lindex $newpath $pos]} {
266         incr pos
267     }
268 
269     # $pos is the index of the first resource along the new branch
270     # (2 in the above example).  $branchpos is the index of the last 
271     # resource along the shared path. (1 in the above example).
272     set branchpos [expr $pos-1]
273 
274     set from [lindex $path $branchpos]
275     set old_to [lindex $path $pos]
276     set new_to [lindex $newpath $pos]
277 
278     # Now split the service from $from->$old_to into $from->$new_to.
279     set dest [$self split_service $flow $new_flow $from $old_to $new_to]
280 
281     # If new destination is created, insert it in to the newpath.
282     if {$dest != {}} {
283         incr pos
284         set newpath [linsert $newpath $pos $dest]
285     }
286 
287     set shared_path [lrange $newpath 0 $branchpos]
288     set new_branch [lrange $newpath $pos end]
289 
290     # Marked the edges along the shared path to be shared (increment the
291     # reference counter)
292     $self share_flow $flow $shared_path 
293 
294     # Copy the services along the shared path from the original flow to 
295     # the new flow.
296     $self for_each_pair from to $shared_path {
297         $new_flow service $from $to [$flow service $from $to]
298     } -nohub
299 
300     # Now create new services along the new path.
301     set dest [$self create_services $new_flow $new_branch $arguments]
302     $self for_each_edge e [lrange $newpath $branchpos end] {
303         $e busy
304     }
305 
306     # Restore the cost (we set it to 0 at the beginning, remember?)
307     $self for_each_edge e $shared_path {
308         $e cost $cost($e)
309     }
310 
311     # It is possible that "create_services" returns a new destination. 
312     # Append it to $newpath.
313     if {$dest != {}} {
314         lappend newpath $dest
315     }
316 
317     # Store the path and flow in the last node of $newpath.
318     $self instvar mob_graph_
319     set last_node [$mob_graph_ get_node [lindex $newpath end]]
320     if {$last_node != ""} {
321         $last_node path $newpath
322         $last_node flow $new_flow
323     } else {
324         MashLog warn "$proc: no such node \"[lindex $newpath end]\""
325     }
326 
327     # Update the flow, commit and return.
328     $new_flow path $newpath
329     $new_flow dest [lindex $newpath end]
330     $new_flow commit
331     return $new_flow
332 }
333 
334 
335 #---------------------------------------------------------------------
336 # Method:
337 #   IndivaManager delete_flow
338 # Description:
339 #   Given a $flow, stop the services, mark the edges as free, and 
340 #   deallocated the flow object.
341 # Side Effects:
342 #   Unused services are stopped.  Services may be stopped as well,
343 #   if it does not have any active services.
344 #---------------------------------------------------------------------
345 IndivaManager public delete_flow { flow } {
346     $self instvar mob_graph_
347     set path [$flow path]
348     $self for_each_pair from to $path {
349         set dest [$self stop_service $flow $from $to ]
350         set e [$mob_graph_ get_edge $from $to]
351         $e free
352     }
353     delete $flow
354 }
355 
356 
357 #---------------------------------------------------------------------
358 # Method:
359 #   IndivaManager redir_service
360 # Description:
361 #   Switch service output of $from to $to.
362 # Arguments:
363 #   flow -- the flow containing the service to be changed.
364 #   from, to -- name of mobs.
365 #---------------------------------------------------------------------
366 IndivaManager instproc redir_service {flow from old_to new_to {arguments ""}} {
367     $self instvar mob_graph_
368     if {[catch {$self get_remote_service $from $new_to} service]} {
369         global errorInfo
370         MashLog warn "$proc: ABORT $errorInfo"
371         $flow abort TIMEOUT
372         return
373     }
374     if {$service == ""} {
375         return
376     }
377     set action [$self get_action_class $from $new_to]
378     set dest [$action redir_service $self $mob_graph_ $service $flow $from $new_to $arguments]
379 
380     set service [$self get_service $from $new_to]
381     $flow service $from $new_to $service
382 
383     return $dest
384 }
385 
386 
387 #---------------------------------------------------------------------
388 # Method:
389 #   IndivaManager split_service
390 # Description:
391 #   There is an existing service belonging to $old_flow, going from 
392 #   $from to $old_to.  This method "split" this service into two, 
393 #   adding a new service that belongs to $new_flow, going from $from
394 #   to $new_to.  The destination returned from $action split_service
395 #   is returned to the caller.
396 # Arguments:
397 #   old_flow, new_flow -- The old and new flows.
398 #   from -- The origin of the service to split.
399 #   old_to, new_to -- The old and new destination of the old and new
400 #     services.
401 #   arguments -- Additional options to pass to the new services.
402 #---------------------------------------------------------------------
403 IndivaManager private split_service {old_flow new_flow from old_to new_to {arguments ""}} {
404     $self instvar mob_graph_ 
405 
406     # Retrieve the service that owns the the service from $from->$old_to.
407     set servent [$self get_servent $from $old_to]
408     if {$servent == ""} {
409         return
410     }
411 
412     # Ask the service to create a new service for us.
413     set service [$servent create_service]
414     if {$service == ""} {
415         return
416     }
417 
418     # Find out what action to take.  (This better be the same action as
419     # $from -> $old_to).  Use the action to split the service.
420     set action [$self get_action_class $from $new_to]
421     set dest [$action split_service $self $mob_graph_ $service $old_flow \
422         $new_flow $from $new_to $arguments]
423 
424     # Add the service into table.
425     set id [$service service_id]
426     $new_flow service $from $new_to $service
427     $self add_service $from $new_to $service $id
428 
429     return $dest
430 }
431 
432 
433 #---------------------------------------------------------------------
434 # Method:
435 #   IndivaManager stop_service
436 # Description:
437 #   Clean-up service going from $from to $to in the given flow.
438 # Arguments:
439 #   flow -- the flow where the service to be stopped belongs.
440 #   from, to -- name of resources.
441 #---------------------------------------------------------------------
442 IndivaManager instproc stop_service { flow from to } {
443     $self instvar mob_graph_ 
444 
445     set service [$flow service $from $to]
446     if {$service == ""} {
447         MashLog info "$proc: No service defined for [short_name $from -> $to]."
448         return
449     }
450     set servent [$self get_servent $from $to]
451     if {$servent == ""} {
452         MashLog warn "$proc: stopping a service without servent?"
453         return
454     }
455 
456     $self instvar service_ref_
457     if ![info exists service_ref_($service)] {
458         $service stop
459         $self delete_service $from $to
460         $servent delete_service $service
461         delete $service
462     } else {
463         incr service_ref_($service) -1
464         if {$service_ref_($service) == 0} {
465             $service stop
466             $self delete_service $from $to
467             $servent delete_service $service
468             delete $service
469         }
470     }
471 
472     if {[$servent num_of_services] == 0} {
473         set ascp [$servent ascp]
474         $self servent unregister [$ascp service_instance]
475         delete $ascp
476     }
477 }
478 
479 
480 #---------------------------------------------------------------------
481 # Method:
482 #   IndivaManager get_action_class
483 # Description:
484 #   Given a list of $froms mob and a $to mob, consult a service table
485 #   to figure out which IMgrAction subclass to use.
486 #---------------------------------------------------------------------
487 IndivaManager instproc get_action_class {froms to} {
488     $self instvar mob_graph_
489     set from [lindex $froms 0]
490     set node [$mob_graph_ get_node $from]
491     set action [$node action]
492     if {$action == "none"} {
493         # try the edge.
494         set edge [$mob_graph_ get_edge $from $to]
495         set action [$edge action]
496 
497         # Make sure that all edges has the same action.
498         foreach from [lrange $froms 1 end] {
499             set edge [$mob_graph_ get_edge $from $to]
500             if {$action != [$edge action]} {
501                 MashLog warn "$proc: WARNING incoming edges has different actions"
502                 return "IMgrAction/None"
503             }
504         }
505     } else {
506         foreach from [lrange $froms 1 end] {
507             set node [$mob_graph_ get_node $from]
508             if {$action != [$node action]} {
509                 MashLog warn "$proc: WARNING incoming node has different actions"
510                 return "IMgrAction/None"
511             }
512         }
513     }
514     set action [string toupper $action 0 0]
515     return "IMgrAction/$action"
516 }
517 
518 
519 #---------------------------------------------------------------------
520 # Method:
521 #   IndivaManager find_path
522 # Description:
523 #   Given the name of a src and a dest, find a path from the src to
524 #   dest.  The path is returned.
525 #---------------------------------------------------------------------
526 IndivaManager instproc find_path {src_name dest_name flow {arguments ""}} {
527 
528     # Plan for execution.  find_paths returns a set of viable
529     # paths to used.  The paths are reverse paths (i.e. from
530     # dest to src. 
531     $self instvar mob_graph_
532     set graph [$mob_graph_ find_paths $src_name $dest_name]
533 
534     set to $dest_name
535     set path $to
536     while {$to != $src_name && ![$flow is_aborted]} {
537         set froms [$graph get_out_neighbors $to]
538         if {$froms == ""} {
539             $flow abort "Unable to find a usable path from [short_name $src_name] to [short_name $dest_name].\n$to has not output neighbor"
540             continue
541         }
542         # If there is only one incoming edge, just return the in-adjacent 
543         # neighbour.
544         if {[llength $froms] == 1} {
545             set from [join $froms]
546         } else {
547             set service [$self get_action_class $froms $to]
548             if {$service == ""} {
549                 error "Unknown service type for $froms $to"
550             }
551             set from [$service get_offer $self $mob_graph_ $flow $froms $to $arguments]
552         }
553         set path [linsert $path 0 $from]
554         set to $from
555     }
556 
557     return $path
558 }
559 
560 
561 #---------------------------------------------------------------------
562 # Method:
563 #   IndivaManager create_services
564 # Description:
565 #   For each pair of mob on the given $path, start the service.  New
566 #   services could be launched as an side effect.
567 #---------------------------------------------------------------------
568 IndivaManager private create_services {flow path {arguments ""}} {
569     set dest ""
570 
571     set from [lindex $path 0]
572     set pos 1
573     set to [lindex $path $pos]
574     while {$to != "" && ![$flow is_aborted]} {
575         set action [$self get_action_class $from $to]
576 
577         # if $to is a hub, we skip over it.
578         if {[MobHub is_hub $to]} {
579             incr pos
580             set to [lindex $path $pos]
581         } 
582 
583         # create the remote service object for this pair of mobs. if a 
584         # service is already running, just return it (nothing is launched). 
585         MashClock start
586 
587         if {[catch {$self create_servent $from $to $arguments} servent]} {
588             global errorInfo
589             MashLog info "$proc: ABORT $errorInfo"
590             $flow abort TIMEOUT
591             return
592         }
593         set t [MashClock stop]
594         MashLog info "create_servent $t ms"
595 
596         # If servent is empty, probably there is no servent associated 
597         # with this pair of mobs.  Skip to the next pair.
598         if {$servent == ""} {
599             set from $to
600             incr pos
601             set to [lindex $path $pos]
602             continue
603         } 
604 
605         # Create the service for this particular pair of mobs.
606         # RPC to the servent, ask for a new service to be created.
607         set service [$servent create_service]
608 
609         $self instvar mob_graph_
610         set dest [$action start_service $self $mob_graph_ \
611             $service $flow $from $to $arguments]
612         set t [MashClock stop]
613         MashLog info "start_service $t ms"
614 
615         # Get the service id for this pair of mobs and store it in 
616         # the flow, and service table.
617         set id [$service service_id]
618         $flow service $from $to $service
619         $self add_service $from $to $service $id
620 
621         # Proceed to the next pair.
622         set from $to
623         incr pos
624         set to [lindex $path $pos]
625     }
626 
627     # If the flow is aborted, delete the flow, and return error.
628     if {[$flow is_aborted]} {
629         set reason [$flow why_abort?]
630         $self delete_flow $flow
631         return -code error -errorcode $reason
632     }
633     return $dest
634 }
635 
636 
637 #---------------------------------------------------------------------
638 # Method:
639 #   IndivaManager share_flow
640 # Description:
641 #   Mark services along a flow as shared (incr its reference count).
642 #---------------------------------------------------------------------
643 IndivaManager private share_flow {flow path} {
644     $self instvar service_ref_
645     $self for_each_pair from to $path {
646         set service [$flow service $from $to]
647         if {$service != ""} {
648             if [info exists service_ref_($service)] {
649                 incr service_ref_($service)
650             } else {
651                 set service_ref_($service) 2
652             }
653         }
654     } -nohub
655 }
656 
657 
658 IndivaManager private get_service_instance {from {to ""}} {
659     $self instvar mob_graph_
660     set ascp [$self get_ascp $from $to]
661     if {$ascp != ""} {
662         return [$ascp service_instance]
663     }
664 
665 }
666 
667 
668 #---------------------------------------------------------------------
669 # Method:
670 #   IndivaManager has_service
671 #   IndivaManager get_service
672 #   IndivaManager add_service
673 #   IndivaManager delete_service
674 # Description:
675 #   Maintain handles to ASCP objects.  
676 #---------------------------------------------------------------------
677 IndivaManager private add_service {from to service id} {
678     $self instvar services_ ascp_
679     set service_key [$self get_service_key $from $to]
680     set services_($service_key) $service
681     set services_by_id_($id) $service
682     set ascp $ascp_($service_key)
683     if {$ascp == ""} {
684         MashLog warn "$proc: WARNING ascp for [short_name $from $to] is empty"
685         MashLog warn "but you are trying to add a service"
686     } else {
687         $ascp on_destroy append "$self delete_service $from $to"
688         $ascp on_service_expire append "$self delete_service $from $to"
689     }
690 }
691 
692 IndivaManager private has_service {from to} {
693     $self instvar services_ 
694     set service_key [$self get_service_key $from $to]
695     if [info exists services_($service_key)] {
696         return 1
697     } else {
698         return 0
699     }
700 }
701 
702 IndivaManager private get_service {from to} {
703     $self instvar services_
704     set service_key [$self get_service_key $from $to]
705     if [info exists services_($service_key)] {
706         return $services_($service_key)
707     } else {
708         return ""
709     }
710 }
711 
712 IndivaManager private get_service_by_id {id} {
713     $self instvar services_by_id_
714     if [info exists services_by_id_($id)] {
715         return $services_by_id_($id)
716     } else {
717         return ""
718     }
719 }
720 
721 IndivaManager private delete_service {from to} {
722     $self instvar services_
723     set service_key [$self get_service_key $from $to]
724     if [info exists services_($service_key)] {
725         unset services_($service_key)
726     } 
727 }
728 
729 IndivaManager private get_service_key {from to} {
730     $self instvar mob_graph_
731     set from_node [$mob_graph_ get_node $from]
732     set to_node [$mob_graph_ get_node $to]
733     set key [$from_node service_key $to_node]
734     return $key
735 }
736 
737 
738 IndivaManager private add_ascp {from to ascp} {
739     $self instvar ascp_
740     set service_key [$self get_service_key $from $to]
741     set ascp_($service_key) $ascp
742 
743     $ascp on_destroy append "$self delete_ascp $from $to"
744     $ascp on_service_expire append "$self delete_ascp $from $to"
745 }
746 
747 IndivaManager private has_ascp {from to} {
748     $self instvar ascp_ 
749     set service_key [$self get_service_key $from $to]
750     if [info exists ascp_($service_key)] {
751         return 1
752     } else {
753         return 0
754     }
755 }
756 
757 IndivaManager private get_ascp {from to} {
758     $self instvar ascp_
759     set service_key [$self get_service_key $from $to]
760     if [info exists ascp_($service_key)] {
761         return $ascp_($service_key)
762     } else {
763         return ""
764     }
765 }
766 
767 IndivaManager private delete_ascp {from to} {
768     $self instvar ascp_
769     set service_key [$self get_service_key $from $to]
770     if [info exists ascp_($service_key)] {
771         unset ascp_($service_key)
772     } 
773 }
774 
775 IndivaManager private get_servent {from to} {
776     set ascp [$self get_ascp $from $to]
777     if {$ascp == ""} {
778         return ""
779     } else {
780         set si [$ascp service_instance]
781         $self instvar servents_
782         if [info exists servents_($si)] {
783             return $servents_($si)
784         } else {
785             MashLog warn "$proc: WARNING there is an ascp for [short_name \
786                 $from -> $to] but there is no service." 
787             return ""
788         }
789     }
790 }
791 
792 
793 
794 #---------------------------------------------------------------------
795 # Method:
796 #   IndivaManager create_servent
797 # Description:
798 #   Launch a remote servent if servent is not already running.  An
799 #   ImgrServent object corresponding to that servent is returned.
800 #   If failed, return empty string.
801 # Postcond:
802 #   If successful, 
803 #   - $self get_ascp $from $to should return an $ascp
804 #   - $servents_([$ascp service_instance]) exists
805 #---------------------------------------------------------------------
806 IndivaManager private create_servent {from to {arguments ""}} {
807     $self instvar mob_graph_ servents_
808     if [catch {$mob_graph_ get_node $from} node] {
809         error "No such mob $from"
810     } 
811     if {$node == ""} {
812         error "No such mob [short_name $from]"
813     }
814 
815     # Get the ASCP object for $from->$to.  If it is not empty, then
816     # a servent already exists.  Just return the servent.
817     set ascp [$self get_ascp $from $to]
818     if {$ascp != ""} {
819         set si [$ascp service_instance]
820         if [info exists servents_($si)] {
821             if {[$servents_($si) is_alive]} {
822                 return $servents_($si)
823             }
824         }
825     }
826 
827     # Servent does not exists.  Launch the servent.
828 
829     # First, find out what action to use.
830     if [catch {$self get_action_class $from $to} action] {
831         set action IMgrAction/None
832     }
833 
834     # Create the service using the associated action.
835     $self instvar mob_graph_ services_
836     set ascp [$action create_servent $self $mob_graph_ $from $to $arguments]
837     if {$ascp == ""} {
838         return
839     }
840 
841     # Wait for the service to start-up and register itself.
842     set si [$ascp service_instance]
843     if {[$self wait_for_register $si] == 0} {
844         return
845     }
846 
847     if {[$servents_($si) is_alive]} {
848 
849         # If the service is alive, which it should, create a new
850         # entry in service table and namespace.
851         $servents_($si) ascp $ascp
852         $self add_ascp $from $to $ascp
853         return $servents_($si)
854 
855     } else {
856 
857         # Else, clean-up the service.
858         $self servent unregister $si
859         $self delete_ascp $from $to
860         return ""
861     } 
862 }
863 
864 
865 #---------------------------------------------------------------------
866 # Method:
867 #   IndivaManager get_remote_service
868 # Description:
869 #   Returns a remote object that controls the mob with given $mob_name
870 #   Returns an empty string if the mob cannot be controlled.
871 # Arguments
872 #   from -- if from is a device, $to is ignored.
873 #---------------------------------------------------------------------
874 IndivaManager private get_remote_service {from {to ""}} {
875     set service [$self get_service $from $to]
876     if {$service == ""} {
877         set servent [$self create_servent $from $to]
878         if {$servent == ""} {
879             return ""
880         }
881         set service [$servent create_service]
882         $self add_service $from $to $service [$service service_id]
883     }
884     return $service
885 
886     #END XP CODE
887 
888     $self instvar mob_graph_ servents_
889     if [catch {$mob_graph_ get_node $from} node] {
890         error "No such mob $from"
891     } 
892     if {$node == ""} {
893         error "No such mob [short_name $from]"
894     }
895 
896     # If the driver for this device is not running, launch the driver
897     if {![$self has_ascp $from $to]} {
898         MashLog info "$proc: no ascp for [short_name $from -> $to]. Creating service.."
899         if [catch {$self get_action_class $from $to} action] {
900             MashLog warn "$proc: WARNING: Error in get_action_class: $action"
901             set action IMgrAction/None
902         }
903         set ascp [$action create_servent $self $mob_graph_ $from $to]
904         if {$ascp == ""} {
905             MashLog warn "$proc: WARNING: $action create_servent $from $to returns empty string"
906             return
907         }
908         set si [$ascp service_instance]
909         if {[$self wait_for_register $si] == 0} {
910             return
911         }
912         if {[$servents_($si) is_alive]} {
913             $servents_($si) ascp $ascp
914             $self add_ascp $from $to $ascp
915             set name [$self mkserv $si]
916 
917             set node [$mob_graph_ get_node $name]
918             $node on_destroy append "$self servent unregister $si"
919             $ascp on_service_expire append "$self rm $name"
920             $ascp on_destroy append "$self rm $name"
921         }
922     } else {
923         set ascp [$self get_ascp $from $to]
924         set si [$ascp service_instance]
925     }
926 
927     if {![$servents_($si) is_alive]} {
928         $self servent unregister $si
929         $self delete_service $from $to
930         # call self to launch driver.
931         return ""
932         #[$self get_remote_service $from $to]
933     } else {
934         set service [$self get_service $from $to]
935         if {$service == ""} {
936             set service [$servents_($si) create_service]
937             $self add_service $from $to $service [$service service_id]
938         }
939         return $