guix-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[shepherd] 01/02: doc: Remove "Runlevel evolution".


From: Ludovic Courtès
Subject: [shepherd] 01/02: doc: Remove "Runlevel evolution".
Date: Sat, 30 May 2020 13:38:02 -0400 (EDT)

civodul pushed a commit to branch master
in repository shepherd.

commit 2c69d7eb116735b36ab0d45ae4cb18b79f33eb31
Author: Ludovic Courtès <ludo@gnu.org>
AuthorDate: Sat May 30 16:38:19 2020 +0200

    doc: Remove "Runlevel evolution".
    
    What's discussed in there is less and less relevant to the actual code.
    
    * doc/shepherd.texi (Runlevel evolution): Remove.
---
 doc/shepherd.texi | 218 ------------------------------------------------------
 1 file changed, 218 deletions(-)

diff --git a/doc/shepherd.texi b/doc/shepherd.texi
index 7217ec2..1de49af 100644
--- a/doc/shepherd.texi
+++ b/doc/shepherd.texi
@@ -1249,7 +1249,6 @@ You're very much welcome to join us!  You can report bugs 
to
 * Coding standards::    How to properly hack the Shepherd.
 * Design decisions::    Why the Shepherd is what it is.
 * Service Internals::   How services actually work.
-* Runlevel evolution::  Learning from past mistakes.
 @end menu
 
 @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -1413,223 +1412,6 @@ understand it), you are welcome to do so, of 
course@dots{}
 
 @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
-@node Runlevel evolution
-@section Runlevel evolution
-
-@quotation Note
-This section was written by Wolfgang Jährling back in 2003 and is kept
-mostly for historians to read.
-@end quotation
-
-This section describes how the runlevel concept evolved over time.
-This is basically a collection of mistakes, but is provided here for
-your information, and possibly for your amusement, but I'm not sure if
-all this weird dependency stuff is really that funny.
-
-@menu
-* Runlevel assumptions::    What runlevels should be like
-* Runlevels - part one::    The first attempts of making it work
-* Runlevels - part two::    It should work... somehow...
-@end menu
-
-@c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
-@node Runlevel assumptions
-@subsection Runlevel assumptions
-
-A runlevel is a system state, i.e. it consists of the information
-about which services are supposed to be available and which not.  This
-vague definition implies that several different runlevel styles can be
-implemented in a service manager.
-
-For example, you can do it like System V Init, specifying which
-services should be started when we enter a runlevel and which ones
-should be stopped when leaving it.  But one could also specify for
-every service in which runlevels it should be running.
-
-In the Shepherd, we do not want to limit ourselfes to a single runlevel style.
-We allow for all possible strategies to be implemented, providing the
-most useful ones as defaults.  We also want to make it possible to
-combine the different styles arbitrariely.
-
-Therefore, when entering a runlevel, we call a user-defined piece of
-code, passing it the list of currently active services and expecting
-as the result a list of service symbols which tell us which services
-we want to have running.  This interface makes it very easy to
-implement runlevel styles, but makes it not-so-easy for the runlevel
-implementation itself, because we have to get from the current state
-into a desired state, which might be more or less vague (since it is
-not required to be a list of canonical names).  Obviously service
-conflicts and already running services need to be taken into account
-when deciding which services should be used to provide the various
-symbols.
-
-Also, the runlevel implementation should be implemented completely on
-top of the service concept, i.e. the service part should not depend on
-the idea of runlevels or care about them at all.  Otherwise
-understanding the service part (which is the most essential aspect of
-the Shepherd) would become harder than necessary.
-
-@c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
-@node Runlevels - part one
-@subsection Runlevels, part one
-
-I came up with the following method (here in Pseudo-Scheme), which is
-possibly slightly buggy, but should give you the idea:
-
-@lisp
-;; Beginning with the canonical names in CURRENT-SERVICES, start and
-;; stop services until getting into a state where everything requested
-;; in TARGET-SERVICES (which does not only consist of canonical names)
-;; is provided, and the things they depends on, but no more.
-(define (switch-runlevel current-services target-services)
-  (let ((target-services-backup target-services)
-       (unstartable '()))
-    (let retry ()
-      (repeat-until-none-of-these-changes-annythig
-       ;; Replace all of them with canonical names which provide them.
-       (canonicalize-names! target-services unstartable current-services)
-       ;; Add what we need additionally.
-       (add-dependencies! target-services unstartable current-services))
-      (remove-redundancy! target-services)
-      (stop-all-unneeded target-services)
-      (catch 'service-could-not-be-started
-            (lambda ()
-              ;; Iterate over the list, starting only those which
-              ;; have all dependencies already resolved, so nothing
-              ;; we don't want will be started.  Repeat until done.
-              (carefully-start target-services))
-            (lambda (key service)
-              (set! unstartable (cons service unstartable))
-              (set! target-services backup-target-services)
-              (set! current-services (compute-current-services))
-              (retry))))))
-@end lisp
-
-This indeed looks like a nice way to get what we want.  However, the
-details of this are not as easy as it looks like.  When replacing
-virtual services with canonical names, we have to be very careful.
-Consider the following situation:
-
-The virtual service X is provided by both A and B, while Y is provided
-only by B.  We want to start C (which depends on X) and D (which
-depends on Y).  Obviously we should use B to fulfill the dependency
-of C and D on X and Y, respectively.  But when we see that we need
-something that provides X, we are likely to do the wrong thing: Select
-A.  Thus, we need to clean this up later. I wanted to do this as
-follows:
-
-While substituting virtual services with canonical names, we also safe
-which one we selected to fulfill what, like this:
-
-@lisp
-((A . (X))
- (B . (Y)))
-@end lisp
-
-Later we look for conflicts, and as A and B conflict, we look which
-one can be removed (things they provide but are not required by anyone
-should be ignored, thus we need to create a list like the above).  In
-this case, we can replace A with B as B also provides X (but A does
-not provide Y, thus the reverse is impossible).  If both could be
-used, we probably should decide which one to use by looking at further
-conflicts, which gets pretty hairy.  But, in this case, we are lucky
-and end up with this:
-
-@lisp
-((B . (X Y)))
-@end lisp
-
-This way of finding out which service we should use in case of
-conflicts sounds pretty sane, but if you think it will work well, you
-have been fooled, because actually it breaks horribly in the following
-situation:
-
-@multitable @columnfractions .10 .30
-@item Service @tab Provides
-@item A @tab @code{W X Y -}
-@item B @tab @code{W X - Z}
-@item C @tab @code{- X Y Z}
-@item D @tab @code{W - - -}
-@end multitable
-
-If we need all of W, X, Y and Z, then obviously we need to take C and
-D.  But if we have a list like this, we cannot fix it:
-
-@lisp
-((A . (W X Y))
- (B . (Z)))
-@end lisp
-
-Thus, we cannot do it this way.
-
-@c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-
-@node Runlevels - part two
-@subsection Runlevels, part two
-
-Let's look again at the table at the end of part two:
-
-@multitable @columnfractions .10 .30
-@item Service @tab Provides
-@item A @tab @code{W X Y -}
-@item B @tab @code{W X - Z}
-@item C @tab @code{- X Y Z}
-@item D @tab @code{W - - -}
-@end multitable
-
-If from this table it is so obvious for us what we should do, then it
-should also be possible to calculate it for a computer, given such a
-table as input.  Ok, we have to take into account conflicts that are
-not visible in this table, but the general idea is usable.  But how do
-we find which combination works?  I found only one way yet: Kind of a
-brute force attack: Try combinations until we find one that works.
-
-This alone would be too slow.  With 20 services we would have 2^20
-possible combinations, that is a bit more than a million.  Fortunately,
-we can optimize this.  First I thought we could remove all services
-from the list that do not provide any symbol we need, but that is
-obviously a stupid idea, as we might need them for dependencies, in
-which case we need to take into account their conflicts.  But the
-following method would work:
-
-Very often a symbol that is required will be a canonical name already,
-i.e. be provided only by a single service.  Using our example above,
-let's suppose we also need the symbol V, which is provided only by D.
-The first step we do is to look which (required) symbols are provided
-only by a single service, as we will need this service for sure.  In
-this case, we would need D.  But by using it, we would also get the
-other symbols it provides, W in this case.  This means that we don't
-need to bother looking at other services that provide W, as we cannot
-use them because they conflict with a service that we definitely need.
-In this case, we can remove A and B from the list this way.  Note that
-we can remove them entirely, as all their conflicts become irrelevant
-to us now.  In this simple case we would not even have to do much
-else, C is the only remaining service.
-
-After this first step, there remain the symbols that are provided by
-two or more services.  In every combination we try, exactly one of
-them must be used (and somehow we should take into account which
-services are running already).  This also reduces the amount of
-possible combinations a lot.  So what remains after that are the
-services we might need for fulfilling dependencies.  For them, we
-could try all combinations (2^n), making sure that we always try
-subsets before any of their supersets to avoid starting unneeded
-services.  We should take into account which services are already
-running as well.
-
-The remaining question is, what to do if starting a service fails.  A
-simple solution would be to recursively remove all services that
-depend on it directly or indirectly.  That might cause undesired
-side-effects, if a service was running but it had to be stopped
-because one of the services that provides something it depends on gets
-exchanged for another service that provides the same symbol, but fails
-to start.  The fact that we would have to stop the (first) service is
-a problem on its own, though.
-
-
-@c *********************************************************************
 @node GNU Free Documentation License
 @appendix GNU Free Documentation License
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]