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 $