1) Which was your Linux distribution story?
Fedora Core 4! I had a brief stint with Ubuntu (measured in hours, not days or weeks), and a long miserable affair with CentOS 4 (Not a desktop OS), but other than that its been Fedora.
2) What is your preferred $your_distribution version?
Fedora 9
3) Write a short story (more like and anecdote) about your past distribution.
Don't ask a question. The answer is always JFGI. Just assume that you know the answer, and then before acting on it, state it loudly, fiercely, and with complete certainty, in a public place, in front of people who know better. Nobody gives information to smart people. Prove you're stupid and they'll devote hours and hours to your education.
Sunday, December 28, 2008
Monday, December 22, 2008
The New Upstart State Machine, Explained in Python
I now have a much less fail example, written in Python. Its incomplete but enough is there.
Get it here
Get it here
Thursday, December 18, 2008
The New Upstart State Machine Part 4
Continued from here.
All we need to make our state machine complete is something to cause holds to be placed from externally. This is where events come into play.
An event can be simply described as "a moment in time at which the hold counter(s) of particular states are increased." We can take this most literally if we look at the cron functionality which has been talked about for upstart for some time.
This means a hold would be placed on
Most events aren't described as precise times though, but rather by a name. Take our
This event would be triggered by DeviceKit itself sending a message to upstart. Take note of the arguments. Events can have parameters just like states, and can match the states they trigger based on them.
Having an event
There's one more case we need. What about those
All we need to make our state machine complete is something to cause holds to be placed from externally. This is where events come into play.
An event can be simply described as "a moment in time at which the hold counter(s) of particular states are increased." We can take this most literally if we look at the cron functionality which has been talked about for upstart for some time.
at 3:53pm logrotate()++This means a hold would be placed on
logrotate() at 3:53pm.Most events aren't described as precise times though, but rather by a name. Take our
found_disk(*) states from the previous part.on devkit.newdisk[label: %1, devname: %2, uuid: %3] : found_disk(label: %1, devname: %2, uuid: %3)++This event would be triggered by DeviceKit itself sending a message to upstart. Take note of the arguments. Events can have parameters just like states, and can match the states they trigger based on them.
Having an event
release a state is a bit stranger. A state can only be stopped by an event when it was started by an event. Furthermore, the particular pair of events must be explicit. Lets refine our found_disk(*) so DeviceKit can remove it when the disk goes away.in devkit.newdisk[label: %1, devname: %2, uuid: %3]..devkit.removeddisk[label: %1, devname: %2, uuid: %3] : found_disk(label: %1, devname: %2, uuid: %3)++There's one more case we need. What about those
mounted(*) states in our last example? We'd like those to be started as soon as they are available.on ɛ : mounted(*)ɛ is an event, which when triggered will start any mounted(*) states. What is unique about ɛ is when it is triggered. ɛ occurs any time something would happen as a result. In the case of mounted(*) it will occur as soon as any dependencies are satisfied. If it is simpler, you can think of ɛ as an event that occurs "every ten-thousandth of a millisecond" or "on every CPU cycle" (I emphasize this is definitely not how it will be implemented). Any state triggered on ɛ will come up at the earliest possible moment.
Tuesday, December 16, 2008
The New Upstart State Machine Part 3
Continued from here.
Well, we have a lot of rules governing when a state can be up, but when does it become up?
Each state has a "hold counter," which is simply a positive integer. When that number is zero, the state is down, when it is nonzero, the state is up. "Placing a hold" means incrementing the hold counter of a state, and "releasing a hold" means decrementing it. It is impossible to hold a state that does not have all of its dependencies satisfied.
This might create a contradiction. Consider the following scenario:
Now, if we place a hold on
The solution is that placing a hold on a state automatically places a hold on all of its dependencies, and releasing a hold on a state automatically releases a hold on each of its dependencies. This keeps their hold counters above zero and keeps the dependency satisfied.
These dependency holds are one of three ways a hold can be placed on a state. The second way is events (described in part 4) and the third is intervention of the system administrator (which becomes useful for things like starting a service by hand).
We now have enough understanding of the system to look at a practical example. Lets look at satisfying /etc/fstab, upstart 1.0 style.
For this exercise, we will look at just three fstab lines:
First, our fstab parsing app parses each of these lines and translates them into the following states:
It then places a hold on all of them.
Meanwhile, in another corner of userspace, DeviceKit places a hold on three other states:
The rest of the logic is dependencies:
Lets look at what is and is not satisfied given this set of dependencies:
Next post we'll explain how to get these three running.
Well, we have a lot of rules governing when a state can be up, but when does it become up?
Each state has a "hold counter," which is simply a positive integer. When that number is zero, the state is down, when it is nonzero, the state is up. "Placing a hold" means incrementing the hold counter of a state, and "releasing a hold" means decrementing it. It is impossible to hold a state that does not have all of its dependencies satisfied.
This might create a contradiction. Consider the following scenario:
astate()→anotherstate()astate()anotherstate()Now, if we place a hold on
astate() it comes up, but what if we then release a hold on anotherstate()? This would cause the dependency to be violated.The solution is that placing a hold on a state automatically places a hold on all of its dependencies, and releasing a hold on a state automatically releases a hold on each of its dependencies. This keeps their hold counters above zero and keeps the dependency satisfied.
These dependency holds are one of three ways a hold can be placed on a state. The second way is events (described in part 4) and the third is intervention of the system administrator (which becomes useful for things like starting a service by hand).
We now have enough understanding of the system to look at a practical example. Lets look at satisfying /etc/fstab, upstart 1.0 style.
For this exercise, we will look at just three fstab lines:
LABEL=myroot / ext3 defaults 1 1foo-nfs.redhat.com:/vol/home/mydocs /home/mydocs nfs rw,nosuid,nodev 0 0UUID=905d2c0a-86bf-4ce6-8f92-27b004284413 swap swap defaults 0 0First, our fstab parsing app parses each of these lines and translates them into the following states:
vol_conf(label: myroot, type: ext3, ops: defaults, fsckpass: 1, freq: 1, mountpoint: /)vol_conf(devname: foo-nfs.redhat.com:/vol/home/mydocs, type: nfs, ops: rw,nosuid,nodev, fsckpass: 0, freq: 0, mountpoint: /home/mydocs)vol_conf(uuid: 905d2c0a-86bf-4ce6-8f92-27b004284413, type: swap, ops: defaults, fsckpass: 0, freq: 0, mountpoint: swap)It then places a hold on all of them.
vol_conf(label: myroot ...)vol_conf(devname: foo-nfs ...)vol_conf(uuid: 905d2c0a ...)Meanwhile, in another corner of userspace, DeviceKit places a hold on three other states:
found_disk(uuid: 905d2c0a..., devname: /dev/sda3, label: swap)found_disk(uuid: de4dbe3f..., devname: /dev/sda1, label: myroot)network_available()The rest of the logic is dependencies:
mounted(uuid: %1, devname: %2, label: %3, type: !nfs, *) → found_disk(uuid: %1, devname: %2, label: %3)
mounted(mountpoint: %1, uuid?: %2, devname?: %3, label?: %4, type: %5) → vol_conf(mountpoint: %1, uuid?: %2, devname?: %3, label?: %4, type: %5)
mounted(type: nfs, mountpoint: %1, devname: %2) → network_available()
Lets look at what is and is not satisfied given this set of dependencies:
mounted(uuid: 905d..., devname: /dev/sda3, type: swap, mountpoint: swap, label: swap)is satisfied for the first dependency (all 3 fields match our firstfound_diskstate), and the second (Our thirdvol_confmatchesmountpoint,uuid, andtype. The other two fields are optional). The third doesn't apply sincetypeis not nfsmounted(type: nfs, mountpoint: /home/mydocs, devname: foo-nfs.redhat.com:/vol/home/mydocsis satisfied for dependency 2 (it matches the secondvol_conf, ignoring the optionaluuidandlabel) and dependency 3 (the network is available). Dependency 1 does not apply, as ourtypeis nfs.mounted(uuid: de4d..., devname: /dev/sda1, type: ext3, mountpoint: /, label: myroot)is satisfied for dependency 1 (again, trivially matches one of ourfound_disks), and for dependency 2 (matches firstvol_conffor all but the optionaluuidanddevnamefields.mounted(uuid: de4d..., devname: /dev/sda1, type: ext3, label: myroot) Is satisfied for dep 1 and does not apply for deps 2 or 3. However, note that it makes no sense (it lacks a mountpoint). We can simply say that such insane states are ignored, and in practice it is fairly easy to implement some simple checks to prevent them from cropping up (they were omitted here for complexity's sake).
Next post we'll explain how to get these three running.
Monday, December 15, 2008
The New Upstart State Machine, Part 2
Continued from here.
With some understanding of states, we can now explain dependencies.
A dependency simply says "state foo cannot be up unless state bar is also up." In this post I reflect this relationship with an arrow (→) which can be read "depends on" (or "implies").
In the above dependency,
Defining dependencies in this manner is rarely useful. Usually we want to define dependencies between large classes of states, not individual ones. For example, suppose we wanted the above dependency to be satisfied for any
In this notation
Suppose we want thystate to have an id, but don't care about its value.
Now the
Its also possible we might have some leeway in what we depend on. Perhaps any
Now
Finally, we will occasionally need to specify a parameter that may or may not be present. We use
This has interesting meaning:
I'm trying to make this as sparse as I know how, and in the process a lot of it feels stranger for the deprivation of context, but hopefully in the coming days, a few more people will know what the hell I'm on about :D
With some understanding of states, we can now explain dependencies.
A dependency simply says "state foo cannot be up unless state bar is also up." In this post I reflect this relationship with an arrow (→) which can be read "depends on" (or "implies").
mystate(crunchy: yes)→thystate(crunchy: yes, id: 7)In the above dependency,
mystate(crunchy: yes) can only be up if thystate(crunchy: yes, id: 7) is up. Take note, mystate(crunchy: no) is not effected by this dependency, as you might expect, but neither is mystate(crunchy: yes, delicious: definitely). Remember, different parameters = different states. thystate in the above example is matched with equal strictness.Defining dependencies in this manner is rarely useful. Usually we want to define dependencies between large classes of states, not individual ones. For example, suppose we wanted the above dependency to be satisfied for any
mystate and thystate with equivalent levels of crunchiness:mystate(crunchy: %1)→thystate(crunchy: %1, id: 7)In this notation
mystate(crunchy: yes) would depend on thystate(crunchy: yes, id: 7), and mystate(crunchy: sometimes) would depend on thystate(crunchy: sometimes, id: 7), etc.Suppose we want thystate to have an id, but don't care about its value.
mystate(crunchy: %1)→thystate(crunchy: %1, id: %2)Now the
id parameter is set to match a pattern which doesn't appear anywhere else, meaning it can accept any value.Its also possible we might have some leeway in what we depend on. Perhaps any
thystate with the two parameters we match will serve our purpose.mystate(crunchy: %1)→thystate(crunchy: %1, id: %2, *)Now
thystate(crunchy: yes, id: 7, crap: 3, morecrap:5) would satisfy mystate(crunchy: yes)'s dependency as well as its more minimal forms above.Finally, we will occasionally need to specify a parameter that may or may not be present. We use
? to denote this:mystate(crunchy: %1)→thystate(crunchy?: %1, id: %2, *)This has interesting meaning:
thystate(crunchy: yes, id: 7) will satisfy the dependency for mystate(crunchy: yes), but thystate(id: 7) will satisfy the dependency for mystate(crunchy: anything).I'm trying to make this as sparse as I know how, and in the process a lot of it feels stranger for the deprivation of context, but hopefully in the coming days, a few more people will know what the hell I'm on about :D
The New Upstart State Machine
Awhile ago I started working on describing a new "service state machine" for Upstart. This would be a departure from the event driven model, and offer a richer mechanism to describe what should be running at any given time. I think I more or less have the design down.
Now if only I could explain it to someone else :)
This series of posts will attempt to explain to mere mortals the abstract workings of this new wonder. Previous descriptions have proven a bit verbose and mathy, so I'm going to take it very slow this time. It may get a bit too easy, but I'm going to take baby steps no matter what.
I should probably note beforehand that the objective here is to develop a body of logic that can describe services, and then from that produce a program that will govern them. This post and ones after will not describe how the state machine should be implemented but how it should behave. For the curious, implementing it has been somewhat crudely and quite inefficiently prototyped here.
So, first we need to define a state. A state consists of 1) a name, 2) a series of properties.
Also, a state is either up or down. Pay attention to those colors, as I will use them consistently here.
There's a lot of comparing of states that will go on shortly, so it is important that we understand what makes states equal.
That last one is important. A state being up or down does not effect its identity for the purposes of comparison.
Now we get into a bit of a mathy idea. Its not hugely complex, but its not entirely intuitive from a computer standpoint. Suppose I were to list a few states inside the state machine:
You know that there are states called
That doesn't seem too rough, but as is so often the case, what isn't said is what's tricky. The list of states above would have the same meaning if you appended the following:
...
The long and short of it is if you see
Now if only I could explain it to someone else :)
This series of posts will attempt to explain to mere mortals the abstract workings of this new wonder. Previous descriptions have proven a bit verbose and mathy, so I'm going to take it very slow this time. It may get a bit too easy, but I'm going to take baby steps no matter what.
I should probably note beforehand that the objective here is to develop a body of logic that can describe services, and then from that produce a program that will govern them. This post and ones after will not describe how the state machine should be implemented but how it should behave. For the curious, implementing it has been somewhat crudely and quite inefficiently prototyped here.
So, first we need to define a state. A state consists of 1) a name, 2) a series of properties.
mystate(crunchy: yes, decaf: no, flavor: immitation_beef)Also, a state is either up or down. Pay attention to those colors, as I will use them consistently here.
There's a lot of comparing of states that will go on shortly, so it is important that we understand what makes states equal.
mystate(crunchy: yes) != mystate(crunchy: no)mystate(crunchy: yes) != thystate(crunchy: yes)mystate(crunchy: yes) == mystate(crunchy: yes)mystate(crunchy: yes, chewy: yes) == mystate(chewy: yes, crunchy: yes)mystate(crunchy: yes) == mystate(crunchy: yes)That last one is important. A state being up or down does not effect its identity for the purposes of comparison.
Now we get into a bit of a mathy idea. Its not hugely complex, but its not entirely intuitive from a computer standpoint. Suppose I were to list a few states inside the state machine:
mystate(crunchy: yes)mystate(crunchy: no, cheesy: yes)mystate(crunchy: no)thystate()thystate(chewy: perhaps)thystate(cheesy: thursdays)You know that there are states called
mystate and thystate. Depending on the context in which this list appeared, it might be safe to assume that a state called frystate doesn't make sense. For any particular state machine, there are only a few possible valid names states can have.That doesn't seem too rough, but as is so often the case, what isn't said is what's tricky. The list of states above would have the same meaning if you appended the following:
mystate(crunchy: maybe)mystate(crunchy: level_1)mystate(crunchy: level_2)mystate(crunchy: level_3)mystate(crunchy: yes, threebears: eleventeen, number: threeve)...
mystate(complete_works_of_shakespeare: ...)The long and short of it is if you see
mystate(anything) you can assume that there exists a mystate with any possible set of parameters you can imagine. The corollary to this is that there are an infinite number of states in any state machine.
Thursday, December 11, 2008
Literate again
I just finished Dave Sedaris' "Naked," the first book I have read through for pleasure in about 2 years. I've spent most of that time joking about my illiteracy, but its termination has rendered it all the more shameful in retrospective.
A copy of "A Tale of Two Cities" has been sitting at just over half done for months. I picked up Sedaris' book 3 days ago and dispatched it swiftly. I don't know that I'm finding Dickens difficult, but the story just hasn't drawn me in. After having largely stuck to the 150-year rule throughout high school, it seems I've lost a taste for the dusty British literature of the canon (or maybe its just not his best). The last time I read I encountered this issue as well. I finished all of Just for Fun in a week after having spent the beginning of the month progressing slowly through Saul Bellow's relatively short "Seize the Day." It seems I've lost patience with most books.
"A Tale of Two Cities" is at least inhibited by footnotes. The historical facts are marked with little numbers and explained in the back of the book, and I check them with an almost OCD-like consistency. This repeated interruption may be making it difficult to follow or be engaged in the story, but I still get the sense that I wouldn't understand as much of what was going on without them. My brain has a tendency to simply discard bits it doesn't understand, only requesting clarification if the result doesn't have a meaning of its own. I can often read large spans without really comprehending, and not realize until several pages later that I've absorbed no nutritional value from the text. It works for conversation too, much to my mother's aggravation. I've been able to acknowledge and participate in entire conversations without any awareness of goings on outside of the TV. Eventually the 5th or 6th of a long line of questioning would be met with a sudden "...wait, what?"
At any rate, the book was wonderful. Sedaris' dry critique of everything, including (perhaps especially) himself, is hysterical. The book is laden with a thorough and delicious sense of the absurd. Its been out awhile, so I'm sure quite a few have read it, but if you haven't, pick it up.
A copy of "A Tale of Two Cities" has been sitting at just over half done for months. I picked up Sedaris' book 3 days ago and dispatched it swiftly. I don't know that I'm finding Dickens difficult, but the story just hasn't drawn me in. After having largely stuck to the 150-year rule throughout high school, it seems I've lost a taste for the dusty British literature of the canon (or maybe its just not his best). The last time I read I encountered this issue as well. I finished all of Just for Fun in a week after having spent the beginning of the month progressing slowly through Saul Bellow's relatively short "Seize the Day." It seems I've lost patience with most books.
"A Tale of Two Cities" is at least inhibited by footnotes. The historical facts are marked with little numbers and explained in the back of the book, and I check them with an almost OCD-like consistency. This repeated interruption may be making it difficult to follow or be engaged in the story, but I still get the sense that I wouldn't understand as much of what was going on without them. My brain has a tendency to simply discard bits it doesn't understand, only requesting clarification if the result doesn't have a meaning of its own. I can often read large spans without really comprehending, and not realize until several pages later that I've absorbed no nutritional value from the text. It works for conversation too, much to my mother's aggravation. I've been able to acknowledge and participate in entire conversations without any awareness of goings on outside of the TV. Eventually the 5th or 6th of a long line of questioning would be met with a sudden "...wait, what?"
At any rate, the book was wonderful. Sedaris' dry critique of everything, including (perhaps especially) himself, is hysterical. The book is laden with a thorough and delicious sense of the absurd. Its been out awhile, so I'm sure quite a few have read it, but if you haven't, pick it up.
Subscribe to:
Posts (Atom)