Mass destruction
The first stage of the repairs in the house wasn't quite in the "repair" category. Indeed, most of the work implied getting raw plaster on the walls and ceilings, removing carpet from the floor, and so on. This task kept us busy from July to October 2009. Since it would be boring to present that kind of activities everywhere in the house, I'll present a few emblematic spots.
The hall is a good example of what we had to face in most rooms on the ground floor.
The wallpaper is quite easy to get rid of, but there's something much, much worse : polystyrene tiles glued on all ceilings. Not only they are quite difficult to remove because of the position you have to be in in order to remove them, but you usually leave pieces of skin on the ceiling and end up bleeding after a few hours. Last but not least, it is impossible to remove the glue without removing pieces of plaster from the ceiling. In the end, we have ceilings which look like fields of round holes.
We ended up with:
- on the one hand somewhat "correct" walls and ceiling, if you ignore the holes which will have to be filled
- plenty of junk which we had to bring to the waste collection centre on a regular basis. We were going there so often that the employees were almost on a first name basis with us !
Another rather interesting place was the living and dining rooms. If you remember the pictures from the origins, these rooms not only had the wonderful polystyrene tiles on the ceiling but also panelling on the walls. Manu had great fun removing them and... the glue...The work in progress provides a wonderful idea of the extent of the issue.
In the end, this allowed us to reach that kind of stage:
Last but not least, the "situation" on the first floor... We had:
- The ever-present polystyrene tiles on the ceilings, of course, which were impossible to unglue without removing part of the paper of the drywalls,
- Moquette on the floors. These went off easily, even if part of them were hidden under a floating floor.
- Moquette on the walls. That was the real pain because some kind of paper layer remained glued on the drywalls and it was awful to unglue it.
For instance, we went through that kind of stage regarding the corridor on the first floor:
... or in one of the bedrooms:
And with much effort, we managed to reach these almost final conditions:
- In the corridor
- In the bedroom:
To be honest it was quite a depressing activity: indeed we were destroying what was somewhat decent in order to reach the raw skeleton of the house. However things would soon improve, which I will explain in a later post.
Criminal incompetence
I have a lot of work to do, and many posts I'd like to write, but that will have to wait. I need to vent some frustration right now.
I am currently on a systems administration mission where I need to inspect and fix (if necessary... lol!) a few virtual servers.
Let's start with the documentation. Oh wait, I can't really start from there. There's nothing. A bunch of IP addresses, a few very weak passwords. A list of a few shell commands, out of the blue. A list of stuff that's been done, or at least I suppose that's what it's supposed to be (the list contains entries such as "Access phpmyadmin", followed by "Change init level"). Nothing to see here, let's move on.
The server's list of virtual hosts includes a SSH gateway, from which you're supposed to connect to the server's other VMs. Well, that sounded fine to me, as it may have meant I wouldn't need to go there and could simply log on through that gateway. Of course, since the "existing" documentation doesn't really list the VM's IP addresses, it's a bit messy. Especially since most ICMP packets seem to be blocked, somewhere, somehow. Oh, and some of the VMs do not listen on port 22. Has it been changed to some other port? Is it being blocked by iptables rules? No fucking clue. In addition, it was possible to log in as root (using a password that wasn't much better than "test") on the gateway.
For now, I've been able to find 3 out of the 11 VMs I'm supposed to take a look at, including the aforementioned gateway. Each host includes the full Gnome desktop, as well as a random assortment of useless stuff (laptop-detect? Dude, it's a VM!). Of course, since the... person... who did this decided to use Ubuntu Server, it's not even possible to remove dbus, because upstart depends on it. Still, I was able to remove a few gigabytes of crap on the servers I could access.
I expect more bad surprises as I keep on working on that. In the meantime, my opinion is that whoever committed this in the first place should seriously think about giving up on systems administration and looking for a career in, oh, I don't know, floor wiping. Or something like that.
The house: origins
So far most posts which we have written and were related to our house were posts regarding the garden. Of course, it was way easier to write them: I had already written them for a gardening forum and all was required was simply copying them and translating them into English. At some point we had to start with the repairs inside the house. However, before getting into that, it is logical to present what we started with. So here are picture we took in Spring 2009 while the former owners still lived there. The idea is to introduce the extend of the work we have to do...
I expect I'll be able to post a few plans to accompany the pictures at some point. For now we only have paper versions and I'll have to scan them first...
Regarding the repairs we intended to do we chose to get some help from a general contractor to help us define exactly what we intended to do, choose the companies who would do the work and manage the day-to-day oversight of the project. In the end here is what was planned (roughly):
- earthwork:
- install a rain water collection tank
- joinery:
- change the kitchen French window, which wasn't of the same model as the others on the ground floor of the house
- install insulated doors in the basement
- install new doors on the 1st floor
- plaster works:
- in the basement, insulate the ceiling and create a new room which would become the server room
- on the ground floor, remove the wall between the hall and the living room, add walls to create cupboards in the hall and the 3 rooms
- on the first floor, line the vertical parts of the walls to increase the insulation and add new walls to fit with the new plan
- electricity:
- replace completely the whole electric installation of the house
- add network cables to connect the whole house for either computer network, phone or TV
- install a network distribution rack in the future server room
- plumbing:
- change completely the heating system (boiler, heaters and network)
- install a new bathroom on the first floor
- connect the house to the town gas network
- set up the rain water network
- replace the old water pumps in the basement
- tiling:
- replace the ugly tiles in the hall, living room, dining room, kitchen and ground floor corridor
- tiling of the toilets and bathroom on the first floor
- tiling of the new server room in the basement
- painting:
- repair and painting of the walls and ceiling of both staircases
We asked for the estimates in July 2009, signed them in September 2009 and actual work by the various contractors started in October. So you can guess there are plenty of opportunities to describe how it went !
Minefield v3.0
I hadn't had the time until now to finish telling the story of our earthwork adventures. Now we're getting close to the end of this episode, so it's probably a good time.
While we were waiting for our friend the plumber to come and save the water tank's pump, I added some sand to make the soil a little less compact; I also replanted the flower beds that had been removed or damaged during the earthworks.
In the flower bed under the balcony, the gaura and the Graham's sage had suffered quite a lot from their staying in buckets (there was a lot of rain then, the buckets were full and the water didn't flow away). The gaura's roots were rotten, and it's dead. I'm giving the sage a chance. I also took the opportunity to make a few changes: adding one of the rosebushes and the caenothus that used to be above the water tank, as well as a few new plants, and making sure the plants were far enough from the path (last time their branches were quite annoying as they were in the way). It looked mostly OK mid-September.
Now, on the side of the water tank's flower bed, I replanted most of the plants that were there before, and I added a few. Still mid-September, it was looking mostly decent again, although one part of it is still quite empty (on the right) and I have a few worries regarding the creeping rosebush which got removed rather brutally by the earthwork contractors. At the time it was quite impossible to break the clods as they were really sticky - and that did not help.
Right now I'm rather encouraged: both the creeping rosebush and the sage are growing new leaves again, so they're not dead. And everything else looks like it's doing OK:
- Under the balcony:
- Above the water tank:
OK, I have to admit it's covered in various weeds I need to remove, and attentive readers will have noticed that there's still a hydrangea in a bucket and a pile of earth in the back above the water tank. The "save the water pump" turned out to be quite epic, as the plumber had to come here 3 times.
- The first time he came, he noticed that the leak was on the outside after he cut through the wall of the server room. And after digging on the outside he discovered that the water junction (which had been changed last year) at the bottom of the drainpipe was leaking. Probably yet another consequence of the earthwork contractor falling
In addition, he didn't have the right pipes to fix the water circuit and when he tried to "hack" it together it ended up with a few geysers. According to Manu he barely avoided being shot in the face by one of these. - The second time he fixed most of the problem but there was still a leak further down the pipe which he didn't see as he couldn't test the circuit.
- The third time he was finally able to complete the repairs.
For now we've kept the hole in the server room's wall for now, until the earthwork contractors come back to fix the water junction. Just in case. In addition, the mini-excavator destroyed the concrete paths, so we'll have to replace them earlier than we'd anticipated...
Who said making the foundations waterproof was a simple job, eh?
Installing Debian GNU/Linux on a LaCie NAS
Since I recently set up Azathoth's 6th revision, I had the old LaCie NAS on a shelf, completely useless. I had to do something with it; however, the system which comes pre-installed on that thing is definitely not too customisable beyond the basics, so I decided to try and install Debian GNU/Linux on it.
One important thing about this old NAS - it uses an Intel EM7210 motherboard, with an Intel 80219 CPU. As it happens, that board is more or less supported by Debian.
However, it is necessary to access the system's RedBoot bootloader, which is only possible using a serial cable whose connector is directly on the motherboard.
Building the cable
The serial cable that allows access to the system's console needs to be plugged on an IDC10 connector. While it might have been possible to use the connector from an old PC along with a null-modem cable, I no longer possess either of these items, so I built my own cable. This is what you need to connect:
| Female DE9 | Female IDC10 |
|---|---|
| 2 | 5 |
| 3 | 3 |
| 5 | 9 |
And if you need a picture for the IDC10 side (I had to look it up, so I might not be the only one in this case):
I hadn't done any soldering for 16 years, so I was a little anxious about that. As it turns out, soldering was the easy part; the wires I used were apparently a little too big for my IDC10 connector, and I broke it. I had to rip connectors from an unused audio front panel and solder them to my wires instead. In addition, since none of my computers here have RS232 interfaces, I had to use an USB<->RS232 adapter.
Minicom settings
The next step was to connect to the NAS's console using Minicom (any serial terminal would do, but I'm used to this one). The settings that need to be used are:
- transfer rate: 115200 bps
- data bits: 8
- parity: none
- stop bits: 1
It is also important to make sure that both hardware and software flow control are turned off.
Booting the Debian installer
Obviously, the next thing to do is to try and start the Debian installer.
In order to do that, it is necessary to boot into the NAS's bootloader, which can be achieved by pressing Ctrl+C in the console before the bootloader's script starts executing (you need to be rather quick, as you only have one second to do so). This leads you to a command prompt.
You will also need to download kernel and RAM disk images for the architecture. Both images can be found on Debian's server (you need to download zImage and initrd.gz).
Once you are ready to proceed, you will need to upload the images to the NAS through the serial cable. Start by telling the bootloader that you want to load the RAM disk image:
load -v -r -b 0x1800000 -m ymodem ramdisk.gz
The bootloader will then expect you to send it the RAM disk's data (the initrd.gz file mentioned above) using YMODEM. In Minicom, that can be done by pressing Ctrl+A followed by S, then selecting "ymodem" in the list, and finally selecting the file to send.
(Wait. Wait some more. Wait even more.)
When that transfer has been completed, you will also need to send it the kernel image by typing
load -v -r -b 0x1008000 -m ymodem zImage
and then sending the zImage file.
(Wait. Wait some more. Wait even more.)
Once both files have been uploaded, you are ready to start the installer. The following command will do just that:
exec -c "console=ttyS0,115200 rw root=/dev/ram mem=256M@0xa0000000" -r 0x01800000
Completing the installation
I've skipped the part about installing Debian, because that's pretty much the usual process. However, there's one additional operation to perform once the installer is done running, as the system will not boot without that. You need to edit the boot script.
In order to do that, when the installer reboots, enter the bootloader by pressing Ctrl+C, then enter the following command:
fconfig boot_script_data
The prompt will change to >> to indicate that you are editing the configuration. You need to set the boot script to this:
fis load -b 0x01800000 ramdisk.gz fis load -b 0x01008000 zImage exec -c "console=ttyS0,115200 rw root=/dev/ram mem=256M@0xa0000000" -r 0x01800000
Don't forget to exit the boot script editor by finishing with an empty line. RedBoot will ask you to confirm the changes then write the configuration to flash memory.
A few notes
- I initially removed the HDDs from the box while trying to boot it in order to avoid unnecessary power cycles. However, if you try to insert them while the Debian installer is running, they will not be detected, and you will end up having to reboot anyway.
- Setting up the partitions takes an awful lot of time, and so does RAID array resynchronisation if that's what you want to use.
Somewhat epic lawn mowing session
Ju and myself both like keeping the lawn a little high, so mowing only occurs once per month under normal circumstances. Lately however we've both been busy with other stuff, and it was bloody hot outside, so the lawn was left to fend for itself for at least 2 months. Today, there were clouds and a rather cool breeze, so I thought I'd do it.
Keep in mind that:
- the lawn isn't that big (400 square meters, give or take),
- something between one fourth and one third of it looks like this:
(I don't know what's to blame; maybe the soil being its usual charming self, or the cherry tree's roots, or the recent heat wave, or maybe some combination of the above), - I had mowed another quarter of it a few weeks ago as I needed something to use as mulch.
And the result is:
... And yes, I did step on both heaps to pack them a little.
PostgreSQL ordered trees, final post
Well, at least I hope it will be the last ;-p
I have recently posted a little about my attempts at making ordered tree structures work in PostgreSQL. While the initial approach works quite well with a single update, trying to re-order the whole tree triggers incoherent behaviour, even with this workaround applied. Because of that, I have given up on triggers and re-implemented the whole ordering code as stored procedures.
A bit of context first, as every case is different:
- the tree is rarely modified, so bad performance isn't much of an issue there;
- it is however very likely for the tree to be modified concurrently;
- all updates to the tree are done through stored procedures, which all lock the whole table before updating anything and then call the re-ordering function once they're done;
- there is at the most one update to the tree for each transaction.
The approach I chose is to compute all ordering paths when the tree is being modified, storing the results in a temporary table, then re-ordering the real table based on these values. Not the most efficient way of doing things, but it has the advantage of actually working.
I started by removing the extra ordering path column, and all ordering triggers.
ALTER TABLE objects
DROP COLUMN object_ordering_path CASCADE;
DROP TRIGGER objects_ordering_bi ON objects;
DROP TRIGGER objects_ordering_bu ON objects;
DROP TRIGGER objects_ordering_au ON objects;
DROP FUNCTION objects_ordering_bi( );
DROP FUNCTION objects_ordering_bu( );
DROP FUNCTION objects_ordering_au( );
The next step was to create a function which computes ordering paths for all known objects. This function needs to go through the objects by order of increasing depth, to make sure that the path to an object's parent has been computed before the path to the object is. It uses a table with two fields: the object's identifier and path.
CREATE OR REPLACE FUNCTION objects_compute_paths( )
RETURNS VOID
STRICT VOLATILE
SECURITY INVOKER
AS $objects_compute_paths$
DECLARE
o_id INT;
o_parent INT;
o_ordering INT;
o_path TEXT;
BEGIN
FOR o_id , o_parent , o_ordering IN
SELECT o.object_id , o.object_id_parent , o.object_ordering
FROM objects o
INNER JOIN objects_tree ot
ON ot.object_id_child = o.object_id
GROUP BY o.object_id , o.object_id_parent , o.object_ordering
ORDER BY MAX( ot.ot_depth )
LOOP
IF o_parent IS NULL THEN
o_path := '';
ELSE
SELECT INTO o_path
object_ordering_path || '/'
FROM objects_ordering
WHERE object_id = o_parent;
END IF;
o_path := o_path || to_char( o_ordering , '000000000000' );
INSERT INTO objects_ordering VALUES ( o_id , o_path );
END LOOP;
END;
$objects_compute_paths$ LANGUAGE plpgsql;
Finally the re-ordering function needs to be replaced so it creates the temporary table, calls the function above to fill it, and then uses that table instead of the main table to re-order the objects.
CREATE OR REPLACE FUNCTION objects_reorder( )
RETURNS VOID
STRICT VOLATILE
SECURITY INVOKER
AS $objects_reorder$
BEGIN
-- Create and fill temporary table
CREATE TEMPORARY TABLE objects_ordering (
object_id INT NOT NULL PRIMARY KEY ,
object_ordering_path TEXT NOT NULL
) ON COMMIT DROP;
PERFORM objects_compute_paths( );
-- Move all rows out of the way
UPDATE objects SET object_ordering = object_ordering + (
SELECT 1 + 2 * MAX( object_ordering ) FROM objects );
-- Re-order objects
UPDATE objects o1 SET object_ordering = 2 * o2.rn
FROM ( SELECT object_id , row_number() OVER(
ORDER BY object_ordering_path ) AS rn
FROM objects_ordering ) o2
WHERE o1.object_id = o2.object_id;
END;
$objects_reorder$ LANGUAGE plpgsql;
Note: there is no object_ordering_path column in the main table any more, but since the objects are always sorted correctly, it is possible to select using the object_ordering integer column to order the objects.
Minefield v2.0
As can be expected from very small companies, our friends the earthwork contractors did not visit us as initially announced. And since we are, as always, really good at being haunted by Murphy's law, there was a rather huge storm on August the 22nd (70 mm of water in only a few hours), just before they actually came. Consequences:
- We spent a lovely morning mopping water from the basement and throwing buckets full of water out in the street. It was definitely an involuntary wet t-shirt contest! Without the neighbour's help we would have been truly flooded.
- I had a lot of plants in buckets outside; well, the buckets were full of water, and I was unable to remove it all. The plants didn't like that
The earthwork contractors came two days after that. But since their secretary had no clue how large an area needed to be prepared, some of the plants we hadn't removed had to be rather savagely dug out or ended up under the heaps of earth that were extracted.
After a full day's work, we have:
- One big heap in the middle of the path,
- A partial trench under the balcony,
- Another trench between the wall and the water tank, with the corresponding heap...
The nice earthwork contractors came back the next day to install a drain as well as a waterproof layer along the wall. Of course, it went catastrophically bad when they discovered their drilling machine was too short and couldn't be used at the right angle to go through the wall and have the drain's pipe join the appropriate sink hole... They really had a hard time!
The earthwork contractors seem to have been contaminated by our tendency to suffer from Murphy's law, and thus it started raining. The soil is sticky, it gets really hard to dig using only a pickaxe and a shovel - so they end up renting a mini-excavator (they had some of these, but theirs were bigger and didn't fit through the gates) in order to finish putting the earth back into the trenches. Which leads to the following:
- The excavator in the middle of my lovely flower bed. It was nice before, wasn't it? :s
- The trench along the water tank being filled again:
And to add insult to injury, one of the contractors fell on the pipe that is used to pump water from the tank and to the taps. They changed the pipe, but it is now impossible to pump water: the pump is no longer primed and water starts flowing under the server room's floor if we try to prime it using the town's water - which means that the pipe must be disconnected or broken somewhere behind the server room's wall... We called the plumber but the guy who came wasn't the one who installed that and didn't dare to try as he doesn't know exactly where the pipes are. So we're waiting for the original plumber to be available so he can fix that...
Triggering inconsistent behaviour with … triggers
Yesterday I ran into something rather weird with PostgreSQL (9.1rc).
A bit of context first: the database in which the problem occurred contains tables which represent an ordered tree, something quite similar to what depesz's post describes; in addition, most of the operations on the structure of the tree are done through stored procedures, and these stored procedures usually re-order the tree's items when they're done.
The main table had a trigger that basically looked like the following:
CREATE OR REPLACE FUNCTION objects_bu( )
RETURNS TRIGGER
SECURITY DEFINER
AS $objects_bu$
BEGIN
-- Various other checks here
IF OLD.object_ordering = NEW.object_ordering
AND OLD.object_id_parent IS NOT DISTINCT FROM NEW.object_id_parent
THEN
RETURN NEW;
END IF;
IF NEW.object_id_parent IS NULL
THEN
NEW.object_ordering_path := to_char( NEW.object_ordering , '000000000000' );
ELSE
SELECT object_ordering_path || '/' || to_char( NEW.object_ordering , '000000000000')
INTO NEW.object_ordering_path
FROM objects
WHERE object_id = NEW.object_id_parent;
END IF;
UPDATE objects
SET object_ordering_path = regexp_replace(
object_ordering_path , '^' || OLD.object_ordering_path, NEW.object_ordering_path )
WHERE object_id IN (
SELECT object_id_child FROM objects_tree
WHERE object_id_parent = NEW.object_id AND ot_depth > 0
);
RETURN NEW;
END;
$objects_bu$ LANGUAGE plpgsql;
CREATE TRIGGER objects_bu
BEFORE UPDATE ON objects FOR EACH ROW
EXECUTE PROCEDURE objects_bu( );
In most cases, this trigger works: it does what it's supposed to do, and the ordering path column is updated just fine. However, if an operation that causes this trigger to execute is followed by another update in the same transaction (for example calling the function that resets the ordering indexes), things get really weird.
For example, if the table contains 3 entries, two of which are children of another, and you try to invert both items (by setting the first item's ordering index to the second item's, plus one) then reorder the tree, it will look like the inversion of the child items did not work. This will not happen systematically - sometimes it will work, but in most cases it won't. Upon closer examination, it appears that:
- the inversion itself works,
- the first update of the re-ordering code sometimes updates all 3 rows (which is what it is supposed to do), but in many cases only changes the rows that have not been updated,
- because that first update "failed" silently, the second update of the re-ordering query will do exactly what it's supposed to do, but since the first child still has its low, non-reordered index, it will stay where it was before the operation.
The whole mess is caused by the last update in the trigger above. It somehow makes PostgreSQL a little confused. To fix it, moving that update to another trigger, which is executed after the update, suffices - and is more logical anyway.
What I am unhappy about here is not the fact that doing updates on the table in a "before update" trigger on the same table does not work. That was a rather silly idea to begin with. But it seems to me that PostgreSQL should behave consistently when that happens - either make it work, or cause an error - instead of going Hannibal Lecter and randomly failing in silence.
I have not reported this bug yet, because it seems related to bug #6123 and I know there is some work in progress on that. Still, this bug results in a behaviour that's weird enough to be worth mentioning.


























