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

Open Mash Cross Reference
mash/tcl/net/rlm.tcl

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

  1 # rlm.tcl --
  2 #
  3 #       FIXME: This file needs a description here.
  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/net/rlm.tcl,v 1.10 2002/02/03 04:28:06 lim Exp $
 32 
 33 
 34 #
 35 # exponential factor for backing off join-timer
 36 #
 37 set rlm_param(alpha) 4
 38 set rlm_param(alpha) 2
 39 set rlm_param(beta) 0.75
 40 set rlm_param(init-tj) 1.5
 41 set rlm_param(init-tj) 10
 42 set rlm_param(init-tj) 5
 43 set rlm_param(init-td) 5
 44 #FIXME
 45 #set rlm_param(init-td) 10
 46 set rlm_param(init-td-var) 2
 47 set rlm_param(max) 600
 48 #FIXME
 49 set rlm_param(max) 60
 50 set rlm_param(g1) 0.25
 51 set rlm_param(g2) 0.25
 52 
 53 #FIXME
 54 #set rlm_param(target-exp-time) 5
 55 #puts stderr "rlm: scaling min-rate by M=$M"
 56 #set rlm_param(max) [expr $rlm_param(target-exp-time) * 60 * $M]
 57 
 58 #FIXME
 59 #puts stderr "rlm: scaling alpha by M=$M"
 60 #set rlm_param(alpha) [expr $rlm_param(alpha) * $M]
 61 
 62 #
 63 # The MMG (Multiple Multicast Groups) class implements the RLM
 64 # protocol (Receiver-driven Layered Multicast).  See
 65 # <a href=http://www.cs.berkeley.edu/~mccanne/phd-work/>McCanne's
 66 # thesis</a> for a detailed description of RLM.<p>
 67 #
 68 # This class implements only the basic protocol machinery, it
 69 # does not know anything about either ns or mash.  MMG is an
 70 # abstract class -- you should not instantiate it directly.
 71 # Instead, to use RLM a subclass needs to be created that
 72 # actually joins and leaves groups, makes upcalls on packet
 73 # losses, etc...<p>
 74 #
 75 # Two such subclasses are implemented at the moment, one for
 76 # ns and one for mash.  Note that since all code in the MMG
 77 # base class is shared between ns and mash, you should not
 78 # change anything in this file without being certain that the
 79 # changes will work properly in both ns and mash.<p>
 80 #
 81 # See documentation for the appropriate subclass (i.e., MMG/ns
 82 # or MMG/mash) for details about RLM in different environments.
 83 Class MMG
 84 
 85 MMG instproc init { levels } {
 86         $self next
 87 
 88         $self instvar debug_ env_ maxlevel_
 89         set debug_ 0
 90         set env_ [lindex [split [$self info class] /] 1]
 91         set maxlevel_ $levels
 92 
 93         #FIXME
 94         global rlm_debug_flag
 95         if [info exists rlm_debug_flag] {
 96                 set debug_ $rlm_debug_flag
 97         }
 98 
 99         $self instvar TD TDVAR state_ subscription_
100         #FIXME
101         global rlm_param
102         set TD $rlm_param(init-td)
103         set TDVAR $rlm_param(init-td-var)
104         set state_ /S
105 
106         #
107         # we number the subscription level starting at 1.
108         # level 0 means no groups are subscribed to.
109         #
110         $self instvar layer_ layers_
111         set i 1
112         while { $i <= $maxlevel_ } {
113                 set layer_($i) [$self create-layer [expr $i - 1]]
114                 lappend layers_ $layer_($i)
115                 incr i
116         }
117 
118         #
119         # set the subscription level to 0 and call add_layer
120         # to start out with at least one group
121         #
122         set subscription_ 0
123         $self add-layer
124 
125         set state_ /S
126 
127         #
128         # Schedule the initial join-timer.
129         #
130         $self set_TJ_timer
131 }
132 
133 MMG instproc set-state s {
134         $self instvar state_
135         set old $state_
136         set state_ $s
137         $self debug "FSM: $old -> $s"
138 }
139 
140 MMG instproc drop-layer {} {
141         $self dumpLevel
142         $self instvar subscription_ layer_
143         set n $subscription_
144 
145         #
146         # if we have an active layer, drop it
147         #
148         if { $n > 0 } {
149                 $self debug "DRP-LAYER $n"
150                 $layer_($n) leave-group
151                 incr n -1
152                 set subscription_ $n
153         }
154         $self dumpLevel
155 }
156 
157 MMG instproc add-layer {} {
158         $self dumpLevel
159         $self instvar maxlevel_ subscription_ layer_
160         set n $subscription_
161         if { $n < $maxlevel_ } {
162                 $self debug "ADD-LAYER"
163                 incr n
164                 set subscription_ $n
165                 $layer_($n) join-group
166         }
167         $self dumpLevel
168 }
169 
170 MMG instproc current_layer_getting_packets {} {
171         $self instvar subscription_ layer_ TD
172         set n $subscription_
173         if { $n == 0 } {
174                 return 0
175         }
176 
177         set l $layer_($subscription_)
178         $self debug "npkts [$l npkts]"
179         if [$l getting-pkts] {
180                 return 1
181         }
182 
183         #FIXME hack to adjust TD for large latency case
184         set delta [expr [$self now] - [$l last-add]]
185         if { $delta > $TD } {
186                 set TD [expr 1.2 * $delta]
187         }
188         return 0
189 }
190 
191 #
192 # return the amount of loss across all the groups of the given mmg
193 #
194 MMG instproc mmg_loss {} {
195         $self instvar layers_
196         set loss 0
197         foreach l $layers_ {
198                 incr loss [$l nlost]
199         }
200         return $loss
201 }
202 
203 #
204 # return the number of packets received across all the groups of the given mmg
205 #
206 MMG instproc mmg_pkts {} {
207         $self instvar layers_
208         set npkts 0
209         foreach l $layers_ {
210                 incr npkts [$l npkts]
211         }
212         return $npkts
213 }
214 
215 #FIXME what is this for?
216 # deleted some code that didn't seem to be used...
217 MMG instproc check-equilibrium {} {
218         global rlm_param
219         $self instvar subscription_ maxlevel_ layer_
220 
221         # see if the next higher-level is maxed out
222         set n [expr $subscription_ + 1]
223         if { $n >= $maxlevel_ || [$layer_($n) timer] >= $rlm_param(max) } {
224                 set eq 1
225         } else {
226                 set eq 0
227         }
228 
229         $self debug "EQ $eq"
230 }
231 
232 MMG instproc backoff-one { n alpha } {
233         $self debug "BACKOFF $n by $alpha"
234         $self instvar layer_
235         $layer_($n) backoff $alpha
236 }
237 
238 MMG instproc backoff n {
239         $self debug "BACKOFF $n"
240         global rlm_param
241         $self instvar maxlevel_ layer_
242         set alpha $rlm_param(alpha)
243         set L $layer_($n)
244         $L backoff $alpha
245         incr n
246         while { $n <= $maxlevel_ } {
247                 $layer_($n) peg-backoff $L
248                 incr n
249         }
250         $self check-equilibrium
251 }
252 
253 MMG instproc highest_level_pending {} {
254         $self instvar maxlevel_
255         set m ""
256         set n 0
257         incr n
258         while { $n <= $maxlevel_ } {
259                 if [$self level_pending $n] {
260                         set m $n
261                 }
262                 incr n
263         }
264         return $m
265 }
266 
267 MMG instproc rlm_update_D  D {
268         #
269         # update detection time estimate
270         #
271         global rlm_param
272         $self instvar TD TDVAR
273 
274         set v [expr abs($D - $TD)]
275         set TD [expr $TD * (1 - $rlm_param(g1)) \
276                                 + $rlm_param(g1) * $D]
277         set TDVAR [expr $TDVAR * (1 - $rlm_param(g2)) \
278                        + $rlm_param(g2) * $v]
279 }
280 
281 MMG instproc exceed_loss_thresh {} {
282         $self instvar h_npkts h_nlost
283         set npkts [expr [$self mmg_pkts] - $h_npkts]
284         if { $npkts >= 10 } {
285                 set nloss [expr [$self mmg_loss] - $h_nlost]
286                 #FIXME 0.4
287                 set loss [expr double($nloss) / ($nloss + $npkts)]
288                 $self debug "H-THRESH $nloss $npkts $loss"
289                 if { $loss > 0.25 } {
290                         return 1
291                 }
292         }
293         return 0
294 }
295 
296 MMG instproc enter_M {} {
297         $self set-state /M
298         $self set_TD_timer_wait
299         $self instvar h_npkts h_nlost
300         set h_npkts [$self mmg_pkts]
301         set h_nlost [$self mmg_loss]
302 }
303 
304 MMG instproc enter_D {} {
305         $self set-state /D
306         $self set_TD_timer_conservative
307 }
308 
309 MMG instproc enter_H {} {
310         $self set_TD_timer_conservative
311         $self set-state /H
312 }
313 
314 MMG instproc log-loss {} {
315         $self debug "LOSS [$self mmg_loss]"
316 
317         $self instvar state_ subscription_ pending_ts_
318         if { $state_ == "/M" } {
319                 if [$self exceed_loss_thresh] {
320                         $self cancel_timer TD
321                         $self drop-layer
322                         $self check-equilibrium
323                         $self enter_D
324                 }
325                 return
326         }
327         if { $state_ == "/S" } {
328                 $self cancel_timer TD
329                 set n [$self highest_level_pending]
330                 if { $n != "" } {
331                         #
332                         # there is a join-experiment in progress --
333                         # back off the join-experiment rate for the
334                         # layer that was doing the experiment
335                         # if we're at that layer, drop it, and
336                         # update the detection time estimator.
337                         #
338                         $self backoff $n
339                         if { $n == $subscription_ } {
340                                 set ts $pending_ts_($subscription_)
341                                 $self rlm_update_D [expr [$self now] - $ts]
342                                 $self drop-layer
343                                 $self check-equilibrium
344                                 $self enter_D
345                                 return
346                         }
347                         #
348                         # If we're at the level just below the experimental
349                         # layer that cause a problem, reset our join timer.
350                         # The logic is that we just effectively ran an
351                         # experiment, so we might as well reset our timer.
352                         # This improves the scalability of the algorithm
353                         # by limiting the frequency of experiments.
354                         #
355                         if { $n == [expr $subscription_ + 1] } {
356                                 $self cancel_timer TJ
357                                 $self set_TJ_timer
358                         }
359                 }
360                 if [$self our_level_recently_added] {
361                         $self enter_M
362                         return
363                 }
364                 $self enter_H
365                 return
366         }
367         if { $state_ == "/H" || $state_ == "/D" } {
368                 return
369         }
370         puts stderr "rlm state machine botched"
371         exit -1
372 }
373 
374 MMG instproc relax_TJ {} {
375         $self instvar subscription_ layer_
376         if { $subscription_ > 0 } {
377                 $layer_($subscription_) relax
378                 $self check-equilibrium
379         }
380 }
381 
382 MMG instproc trigger_TD {} {
383         $self instvar state_
384         if { $state_ == "/H" } {
385                 $self enter_M
386                 return
387         }
388         if { $state_ == "/D" || $state_ == "/M" } {
389                 $self set-state /S
390                 $self set_TD_timer_conservative
391                 return
392         }
393         if { $state_ == "/S" } {
394                 $self relax_TJ
395                 $self set_TD_timer_conservative
396                 return
397         }
398         puts stderr "trigger_TD: rlm state machine botched $state)"
399         exit -1
400 }
401 
402 MMG instproc set_TJ_timer {} {
403         global rlm_param
404         $self instvar subscription_ layer_
405         set n [expr $subscription_ + 1]
406         if ![info exists layer_($n)] {
407                 #
408                 # no timer -- means we're maximally subscribed
409                 #
410                 return
411         }
412         set I [$layer_($n) timer]
413         set d [expr $I / 2.0 + [trunc_exponential $I]]
414         $self debug "TJ $d"
415         $self set_timer TJ $d
416 }
417 
418 MMG instproc set_TD_timer_conservative {} {
419         $self instvar TD TDVAR
420         set delay [expr $TD + 1.5 * $TDVAR]
421         $self set_timer TD $delay
422 }
423 
424 MMG instproc set_TD_timer_wait {} {
425         $self instvar TD TDVAR
426         #FIXME factor of 2?
427         $self instvar subscription_
428         set k [expr $subscription_ / 2. + 1.5]
429         #       set k 2
430         $self set_timer TD [expr $TD + $k * $TDVAR]
431 }
432 
433 #
434 # Return true iff the time given by $ts is recent enough
435 # such that any action taken since then is likely to influence the
436 # present or future
437 #
438 MMG instproc is-recent { ts } {
439         $self instvar TD TDVAR
440         set ts [expr $ts + ($TD + 2 * $TDVAR)]
441         if { $ts > [$self now] } {
442                 return 1
443         }
444         return 0
445 }
446 
447 MMG instproc level_pending n {
448         $self instvar pending_ts_
449         if { [info exists pending_ts_($n)] && \
450                  [$self is-recent $pending_ts_($n)] } {
451                 return 1
452         }
453         return 0
454 }
455 
456 MMG instproc level_recently_joined n {
457         $self instvar join_ts_
458         if { [info exists join_ts_($n)] && \
459                  [$self is-recent $join_ts_($n)] } {
460                 return 1
461         }
462         return 0
463 }
464 
465 MMG instproc pending_inferior_jexps {} {
466         set n 0
467         $self instvar subscription_
468         while { $n <= $subscription_ } {
469                 if [$self level_recently_joined $n] {
470                         return 1
471                 }
472                 incr n
473         }
474         $self debug "NO-PEND-INF"
475         return 0
476 }
477 
478 #
479 # join the next higher layer when in /S
480 #
481 MMG instproc trigger_TJ {} {
482         $self debug "trigger-TJ"
483         $self instvar state_ ctrl_ subscription_
484         if { ($state_ == "/S" && ![$self pending_inferior_jexps] && \
485                   [$self current_layer_getting_packets])  } {
486                 $self add-layer
487                 $self check-equilibrium
488                 set msg "add $subscription_"
489                 $ctrl_ send $msg
490                 #FIXME loop back message
491                 $self local-join
492         }
493         $self set_TJ_timer
494 }
495 
496 MMG instproc our_level_recently_added {} {
497         $self instvar subscription_ layer_
498         return [$self is-recent [$layer_($subscription_) last-add]]
499 }
500 
501 
502 MMG instproc recv-ctrl msg {
503         $self instvar join_ts_ pending_ts_ subscription_
504         $self debug "X-JOIN $msg"
505         set what [lindex $msg 0]
506         if { $what != "add" } {
507                 #puts RECV/$msg
508                 return
509         }
510         set level [lindex $msg 1]
511         #
512         #FIXME
513         # only set the join-ts if the outside J.E. is greater
514         # than our level.  if not, then we do not want to falsely
515         # increase the ts of our levels.FIXME say this better.
516         #
517         set join_ts_($level) [$self now]
518         if { $level > $subscription_ } {
519                 set pending_ts_($level) [$self now]
520         }
521 }
522 
523 MMG instproc local-join {} {
524         $self instvar subscription_ pending_ts_ join_ts_
525         set join_ts_($subscription_) [$self now]
526         set pending_ts_($subscription_) [$self now]
527 }
528 
529 MMG instproc debug { msg } {
530         $self instvar debug_ subscription_ state_
531         if {$debug_} {
532                 puts stderr "[gettimeofday] layer $subscription_ $state_ $msg"
533         }
534 }
535 
536 #FIXME
537 MMG instproc dumpLevel {} {
538 #       global rlmTraceFile rates
539 #       if [info exists rlmTraceFile] {
540 #               $self instvar subscription node rateMap
541 #               #FIXME
542 #               if ![info exists rateMap] {
543 #                       set s 0
544 #                       set rateMap ""
545 #                       foreach r $rates {
546 #                               set s [expr $s + $r]
547 #                               lappend rateMap $s
548 #                       }
549 #               }
550 #               set r [lindex $rateMap $subscription]
551 #               puts $rlmTraceFile "[$node id] [ns-now] $r"
552 #       }
553 }
554 
555 
556 
557 Class Layer
558 
559 Layer instproc init { mmg } {
560         $self next
561 
562         $self instvar mmg_ TJ npkts_
563         global rlm_param
564         set mmg_ $mmg
565         set TJ $rlm_param(init-tj)
566         set npkts_ 0
567         # loss trace created in constructor of derived class
568 }
569 
570 #Layer should relax by beta and not alpha
571 Layer instproc relax {} {
572         global rlm_param
573         $self instvar TJ
574         set TJ [expr $TJ * $rlm_param(beta)]
575         if { $TJ <= $rlm_param(init-tj) } {
576                 set TJ $rlm_param(init-tj)
577         }
578 }
579 
580 Layer instproc backoff alpha {
581         global rlm_param
582         $self instvar TJ
583         set TJ [expr $TJ * $alpha]
584         if { $TJ >= $rlm_param(max) } {
585                 set TJ $rlm_param(max)
586         }
587 }
588 
589 Layer instproc peg-backoff L {
590         $self instvar TJ
591         set t [$L set TJ]
592         if { $t >= $TJ } {
593                 set TJ $t
594         }
595 }
596 
597 Layer instproc timer {} {
598         $self instvar TJ
599         return $TJ
600 }
601 
602 Layer instproc last-add {} {
603         $self instvar add_time_
604         return $add_time_
605 }
606 
607 Layer instproc join-group {} {
608         $self instvar npkts_ add_time_ mmg_
609         set npkts_ [$self npkts]
610         set add_time_ [$mmg_ now]
611         # derived class actually joins group
612 }
613 
614 Layer instproc leave-group {} {
615         # derived class actually leaves group
616 }
617 
618 Layer instproc getting-pkts {} {
619         $self instvar npkts_
620         return [expr [$self npkts] != $npkts_]
621 }
622 

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

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.