Friday, December 24, 2010

Christmas Star

I grew up with my parents, the only child.

I also grew up with friends, and had very tight and warm family ties with my father's sister's children - my cousins, my brothers in spirit.

About twenty years ago, my father's health had declined so much that he could hardly work. He had recently been laid off, as a part of cutbacks just before his employer went bankrupt. Physical labour was hard on him, and we, his family, did not understand why, how, or how much. He received unemployment benefits as long as that was permissible, and then he got a job with an old friend, who owned a technical clothing store. That did not work out very well, because it was really tough on father to walk among aisles and restocking clothes. He even fainted once.

The late eighties and nineties were wondrous times in many ways, but the medical profession had hardly heard about ME or COLD/COPD as we know these classifications today. Getting medical recognition that my father was effectively unable to work was almost impossible, particularly considering that he – as so many from his generation – was a smoker. If you have any kind of problems with general shortness of breath, and a doctor asks you, "do you smoke", answering "yes" was then (and apparently still is) a very, very bad idea. The smoking then becomes the only focus, and the rest of the patient's problems seem pretty irrelevant.

But my father did get his disability pension.

In 1994, his father - my grandfather - fell in the snow and froze to death. He had been a widower for five years. Father and his sister inherited a small farm house with a little bit of land, in Vang in Hedmark. My parents sold our house in Oslo, bought my aunt's share, and moved. I moved to an apartment in a more central location in Oslo.

It was strange to not see my parents every day anymore, but it was also a sort of relief - a young grown-up probably benefits from moving, and I think I did. I certainly felt it was over due. :) But I kept regularly in touch with my parents, visited them every month or so, and we continued spending Christmas together every year, with my surviving grandmother, as we had for every Christmas since I was born in 1972.

Through the years, my father's health kept declining, and he became less and less active. Traveling became a chore.

In 2001, a very good friend of mine was diagnosed with particularly aggressive melanoma, but there was hope.

Around the same time, my father's health was so bad that he hardly walked around, and he didn't drive a car anymore because he thought it was irresponsible and unsafe. My parents sold the farm house and the land in 2002, and moved to an apartment in central Hamar. The apartment was fairly well suited for the elderly and disabled, and it saved my mother lots of house and garden work - which of course my father could take no part in.

My friend's cancer spread.

I still celebrated Christmas with my parents, every after grandmother died in 2003. The same year, my friend collapsed in my arms in a seemingly epileptic fit. That was a brain tumour. The same spring, they discovered that the cancer had spread to his colon. A few friends and I were visiting him a fine May day, when he suddenly panicked, started hyperventilating, pressed his pain pump's button repeatedly and pulled the alarm string. We were ushered out by the nurses. Five minutes later, he died, shortly before his family came to see him.

A couple of years later, my father was completely dependent on an electrical wheelchair, a chair or a bed - standing unaided was a risky affair. My mother and father rarely left Hamar, socially or otherwise. This was a pretty heavy burden for us to bear, my parents were both socially active before, and had many good friends. My mother was diagnosed with operable breast cancer in 2005, and the tumour and lymph cysts were surgically removed within a couple of weeks.

I had started sleeping with my phone next to my pillow.

We still celebrated Christmas together, and in 2007, my father took a chance, and visited his sister in Oslo for her 70th birthday. It was a wonderful day.

I never went anywhere without my cellphone, and made sure that I had the wireless house phone with me even in the bathroom.

In the summer of 2008, my father's brother-in-law, my uncle, was admitted to hospital because of what he thought was severe constipation. It wasn't, it was cancer. I visited him about half-way into his first week in hospital, and he was already so weak that he couldn't sit up and had to wear an oxygen mask, but he was fairly lucid. But he looked no healthier than my friend did just before he died, and right enough, a week later, my uncle was dead. My aunt and my cousins still came for my father's 70th birthday shortly afterwards, and it was a very fine celebration, despite that I had to drive my father home early because he was too tired.

My father went through a lot in those later years. He broke his hip from a fall indoors, and he needed extensive home care. He was frequently in the hospital for emergency care. I started having trouble sleeping, and was constantly worried for The Phone Call.

Late in 2008, my father was admitted to palliative care at Prestrud in Hamar, it was now too hard and difficult to care for him at home. My father had probably already suffered brain damage from lack of oxygen - which was untreated, because, hey, he was a smoker, and he just couldn't stop smoking - his withdrawal symptoms were too bad. And, hey, if you don't stop smoking, you don't get proper medical care.

My mother and I still hoped that we could celebrate Christmas in their apartment, but it was soon obvious that it would be impossible. So we prepared to celebrate part of Christmas with him at Prestrud.

I recall that Christmas Eve more vividly than most. My mother and I followed most of the old routine. The TV was on, and the traditional movie "The Journey to the Christmas Star" was showing as it always is. A character, Sonja, sings the song "Christmas Star, come to me", and I start crying.

We visited father at Prestrud, had Christmas cookies, biscuits, hot chocolate with cream and a good time, all considering.

A day in February, my mother called me at work. Father had pneumonia. I told my boss that I had to go, and went home to pack. Shortly afterwards, my mother called again; father was dead.

It was a strange funeral. Warm and melancholic, a wonderful priest - Helge Hognestad - who had an exceptional grasp of the humanity of it all. The first part of the funeral was tough going for me, but then I held my speech for father, and talked about many of the good things and times that I associate with him. Carrying his casket was tough, too, but when the hearse drove off, I was so relieved that I couldn't stop smiling.

Father's suffering was over. Mother's suffering was over. My suffering was over, too.

But then came the double whammy: in late spring, mother was diagnosed with pancreatic cancer, the kind which has seen an amazing increase in surviving patients, then at an estimated whopping 5%. It was a very hard blow, but then my mother and I started talking about it, and she decided to live her life in full, for however long that was.

In spite of awful side effects from chemo therapy, in spite of bloody vomit and other unsavory details, she kept on going. We went traveling together twice, my mother went alone or with others several times. She sometimes had to cancel before going, sometimes had to abort the vacation half way, but she never really gave up. We kept more in touch than before, talking at least every week, and meeting once or twice a month. We talked about good things and bad, and had a stronger relationship than in many years.

She started dancing swing again. She took up bridge, which she thought she was awfully bad at after so many years. She did almost all the things she couldn't do while father was too ill to go anywhere, or too ill to be left alone.

Her health kept declining, in some ways much as my father's had, but far quicker and therefore more visibly. Nobody blamed smoking, though.

She got help from Hospice Sangen, a day facility for people with severe illnesses, particularly cancer patients. She had an "open return" at Hamar hospital, in case she needed medical care, there was always room there. She got home care from nurses, whenever necessary, and at regular intervals with increasing frequency.

This fall, she was admitted to Hospice Lovisenberg, Sangen's "mother" facility in Oslo, for help with her significant pain medication problems; the medication just wouldn't take. She was fairly active while she stayed at Lovisenberg. Two Saturdays, she went shopping with me, the first time also with her elder sister. Lovisenberg got the pain sorted out, and on Monday a month ago - my birthday - I drove her home to Hamar again, thinking that she seemed a bit tired and reduced, but all understandable, since she had been stressing herself out a bit with packing and whatnot. Besides, she had been getting enough morphine to kill grown men several times over, on a regular basis, for weeks.

The following Wednesday, we talked on the phone again. She was more tired, and felt a bit unsteady on her legs, and had therefore gotten a four-wheel walker. I decided that I wanted to check up on her after the coming weekend, which was full of plans for myself - birthday party, roleplaying, etc. I told her I was coming the following Monday, and she was happy that I wanted to.

I called again on Friday during lunch hour, and my mother said: "I don't have much time left now, Jan. Can you talk to my sister?" and handed the phone over to her sister (not the same who went shopping with us just two weeks earlier). She explained to me that mother was lying on the couch (as she often did when she felt tired), but that she had hardly eaten that day, and my aunt didn't dare leave her alone. I said I'd try to get there this weekend.

I talked to my boss again, tidied up a few pressing tasks at work, went home and packed. I cancelled the party and notified others that I was not coming for roleplaying or other social events. I then told my mother and aunt that I was coming that evening, got into the car, and did as I said.

When I got there, we got help from a nurse so that mother could get to bed and sleep there. She was very tired, and barely coherent, though she heard and understood us.

The following morning, mother couldn't even sit up without aid, and she could not drink and swallow her pills without help. My aunt came back during the day, and we convinced a supervising nurse to have a look at my mother's now fairly swollen legs. We then convinced the nurse to call for an ambulance, and had mother admitted to the hospital that Saturday night.

At hospital, I called my youngest cousin, the closest person I've had to a brother, and told him briefly how it was. He said he'd come and keep me company.

During the night, mother had occasional pain in spite of the better pain medication and well-adjusted morphine pump, and occasionally lucid moments. Her breathing was laboured, but when the nurses managed to adjust the morphine dosage up by a third and the bolus frequency limit down by a third, she was well relieved. I had to push the button, though, because my mother could not.

In the early morning, her breathing slowed and became weaker. She was sleeping or dozing all the while, and I was holding her hand, and my cousin was holding mine.

Her face was tilted slightly towards me, and one eyelid was slightly ajar, the pupil aligned with my face. She died so peacefully that I can't say exactly when it was. It was beautiful, and I wouldn't have missed it for the world.

But I miss you, mother, and most of all today, and now I think of Sonja's song and cry.

Sunday, August 1, 2010

Community boost

It is now three days since the release of Rakudo Star.

Everything has met my personal expectations, except for one major thing:

There is a bunch of new people on #perl6, who are actively engaged in trying out Rakudo Star/Perl 6, in testing, submitting bug reports, patch suggestions, asking for help, providing help, helping themselves…

I really do not have anything profound to say, but I can say this:

Now we are really getting somewhere!

Thursday, July 29, 2010

Rakudo Star is here

The wait is over, and a usable Rakudo-based Perl 6 distribution is ready for early adopters. Yay!

More and more of Perl 6 is implemented in Perl 6. That is a very good tendency.

Thursday, March 4, 2010

Coding styles that make me twitch, part 8

One of the worst programming habits I know of, is assuming that everything will work out; you just perform the command/function call, and it has to work. In other words: do not bother checking for error conditions or propagating them, because they are not going to happen anyway. right?

Wrong.

But the code works. Mostly. Except when an error condition occurs. And it will, eventually.

In some instances, such code is a glorified shell script. I have ranted about that before. But catching error conditions properly can be tricker than with in-Perl functions and modules. Especially if you have no control over what the external program does, but the original programmer did.

Even with in-Perl functions and modules, you might run into, ehrm, interesting usage.

Usually, the root of the problem is that the original programmer did not foresee that some his code could grow into something else.

While it may have been a good idea to create an SQL query wrapper to hide parts of what DBI does for auto-committing statements:
sub do_sql {
my $qry = shift;
my $ignore = shift;
if (!$dh) {
&slogin();
return if (!$dh);
}
my $sh = $dh->prepare($qry);
if ($sh && !$sh->execute) {
if ($sh->errstr =~ /(MySQL server has\
gone away)|(Lost connection to MySQL server)/) {
&log("Lost MySQL, reconnecting.");
&slogin();
return if (!$dh);
$sh = $dh->prepare($sqlstmt);
undef $sh if ($sh && !$sh->execute);
} else {
undef $sh;
}
}
&log("SQL failed: '$qry'.") if (!$sh && !$ignore);
return $sh;
}

that is no guarantee that the implementation will be future-proof, when the subroutine is used like this:
my $sh=&do_sql("SELECT * FROM tab1 WHERE\
x<>'$cgi->{data}' AND y<>42");
if (my $res=$sh->fetchrow_hashref) {
$cgi->{ref}=$res->{ref};
}
&do_sql("UPDATE tab1 SET x='$cgi->{newdata}',\
y=23, z='$cgi->{ref}'");
&do_sql("UPDATE tab2 SET tab1_changed='yes'");
&log("Updated tab1, ready for externals");
# Process the changes made above:
system("/usr/local/bin/changestuff.pl");
&log("Finished processing");

Imagine now that changestuff.pl also performs changes in the database tables mentioned above, and that the code above is called in a cron job every minute or so.

Here is an attempt at listing the worst parts:
  • do_sql only pretends to do proper error checking, it mostly does not do anything useful about the error situations.
  • The query result seems of little consequence.
  • There is an obvious need for bound variables in the prepared statement, but do_sql does not support that. So the code pretends the problem does not exist.
  • When do_sql is used for updates, there is no check whether the returned statement handle ($sh) is empty or not, there is no way of knowing whether we are clobbering the database.
  • Why do we not care whether the external commands succeeds or not?
  • SQL transactions, anyone?
  • Yeah, other parts of the style sucks, too.
Now imagine the example above multiplied to thousands of lines of inter-dependant code.

I am happy to say that I do not see things like this too often.

However, cleaning up code like this is a PITA, and it is often easier just to close your eyes, add your own code, and leave well enough alone.

Thursday, February 25, 2010

Coding styles that make me twitch, part 7

Parentheses and precedence

This week, I will strive to be better at explaining the problem scope, while heroically and miraculously maintaining brevity.

I used to be annoyed at seeing extraneous parentheses with the ternary conditional operator pair ? :, but then I discovered that the PHP language designers decided to break precedence (see example #3). So I have stopped twitching as much as I used to when seeing parentheses galore in that context.

In Perl Best Practices, Damian Conway notes that even though the low-precedence logic operators and, not and or may seem nicer, they can confuse the reader regarding the intended meaning of the code. But he does not — as far as I can recall or find — address how these relates to parentheses and precedence (I suppose that should be "parentheses && precedence").

I start twitching when someone insists on using parentheses like this (imagine that the example was more convoluted):
if (expr1 ||
(expr2 && expr3) ||
expr4
...)
That does not help understanding. It confuses me, as the read, regarding your intentions. Is there a piece of code missing, perhaps a little bit of || expr2b or || expr3b?

Sometimes, I even see misguidedly mixed-in letter-literal operators:
if (expr1 or
(expr2 && expr3) or
(!expr4)
...)

I much prefer seeing
if (expr1 ||
expr2 && expr3 ||
expr4
...)
or
if (expr1
|| expr2 && expr3
|| expr4
...)
depending on what floats your boat in the most stylish way imaginable.

I would have thought that the logical and/or/not part of operator precedence would be easy to understand. It is essentially the same in most programming languages: Ruby, Python, Perl, Java, C, ... and not even PHP managed to mess this one up.

The chance that anyone is going to be confused by your code because of these parentheses not being there is far, far smaller than the chance that they are going to be confused by their presence.

I have heard the defense "but the code is so non-obvious that I had to add them!" Well, make your code obvious instead.

Thursday, February 18, 2010

Coding styles that make me twitch, part 6

Edit: There are, apparently, strong feelings that I should not post my personal preferences. Reader discretion advised: this post expresses my personal opinions regarding a limited use case for file handling and filehandles, and must not be read as general advise on how to deal with filehandles in Perl, and so on.

Today's theme is: unnecessary variable clutter.
my $fh = new Filehandle("/usr/bin/somecmd someargs |");
while (my $l=<$fh>) {
if ($l=~m/foo bar zot/) {
# lots of code that does not depend on
# a variable file handle, nor creative
# usage of $l where $_ could not be used
# implicitly just as easily

}
}
Sure, there are situations where it makes sense to assign filehandles to variables, or using $l instead of $_, but the above example is not one of them. I found no particular reason why the original programmer had used new Filehandle, either.

Perl 5 has, on purpose, made this easier for us than in the above example:
open my $FH, '-|', '/usr/bin/somecmd someargs'
or croak "OMG\n";
while (<$FH>) {
if (/foo bar zot/) {
# lots of code
}
}

Thursday, February 11, 2010

Missing feature

A few hours ago, I suddenly had a bright(?) idea, or desire if you will:

Proper (Unicode) exponents in Perl.

That is, I want to be able to write 22, 4137, 3-9, etc. and have Perl understand them.

For Perl 5, I suspect someone would use a source filter to implement it.

For Perl 6, PerlJam++ suggested introducing each of the exponents as postfix operators, using this example for squaring:
our &postfix:<2> := &infix:<**>.assuming(b => 2);
But then a negative exponent would complicate things a bit.

It's a thought, anyway, and not one that I'd want to distract more pressing implementation concerns.

And ifwhen someone decides that this is a good idea to have in the language core, I'll start nagging about Knuth's up-arrow notation. Not that I'd want anyone attempt calculating 4↑↑↑↑4.

Thursday, February 4, 2010

Spooky

This is just a small anecdote.

Tonight, I finished a small Perl 5 script that I've been wanting to complete for a while, but where I was a bit nervous that I'd fsck it up right and good.

It was a script designed to handle two tab-separated text sources; one a list of tournament IDs and tournament names, the other a list of player results, one line per result with the player ID, tournament name, position and score achieved.

I achieved this by creating a hash of hashes for each file, referencing the first while parsing the other, and bravely inserting the data into a single database table.

I tested my code piece for piece while building it, which is sensible in itself, but what spooked me was this:

There was not a single bug. The script did what it was supposed to do, all along.

That's not supposed to happen.

I need a drink.

Friday, January 29, 2010

Rakudo ng - what will it mean for us?

If you've been hanging around the right blogs and the #perl6 IRC channel on Freenode, then you've probably seen references to a slightly mysterious "ng", or "Rakudo ng".

That's the upcoming (next) version (generation) of Rakudo, which will form the basis for Rakudo *.

In essence, this is a refactoring/rewrite of Rakudo for the purpose of better compliance with the specification and performance improvements (yay). The old Rakudo master made it difficult — if not impossible — to implement several essential parts of the Perl 6 spec and top priorities on the Rakudo roadmap.

In January, this has led to less focus on the current Rakudo version's bugs and gotchas, and instead on working to prepare ng as the new master branch — that is, the Rakudo that you will be downloading the next time.

For those of us who do some Perl 6 coding in Rakudo, this means that we can expect a nice little bunch of incompatibilities as compared to the current master. And yes, it's very close, so it's time to prepare.

Here's a list of the blindingly obvious things I think we need to watch out for:
  • Older Rakudo was not in line with parts of the spec that ng will be.
  • The spec has changed. (ng development has uncovered several necessary changes.)
  • Older Rakudo is in line with parts of the spec that ng perhaps isn't.
  • Rakudo ng is, of course, not feature complete when it replaces older Rakudo as the master.

In other words: let's not fool ourselves into thinking that we all of a sudden have a new Rakudo that's both compatible with the older as well as being spec compliant.

The good news about Rakudo ng

If you judge by the above paragraphs, you'd think that Rakudo ng was bad for Perl 6 developers. But that's far off the mark. I prodded #perl6 and Patrick Michaud before publishing this post, and here's a brief summary of (most of) the improvements we can see coming with Rakudo ng as opposed to the current implementation.

  • Most of the top priorities of the Rakudo roadmap will be implemented!
  • Laziness will mostly work (the spec is undergoing change)
  • Performance improvements, many due to laziness
  • Array/List/Parcel/etc. will be compliant with the updated spec
  • Protoregexes
  • Better longest token matching
  • Meta-operators are really meta, and generated on demand
  • The base object metamodel is far closer to the spec than before
  • Major portions of the metamodel are implemented in Perl 6
  • Array and hash vivification will work properly
  • Lexical subs and variables work properly
  • Operators have the correct names (with angles)
  • Subs have the correct sigils (with ampersands)
  • Phasers work, and the phaser model is much improved

Our programs will need a bit of attention. I recommend subscribing to perl6-language for up-to-date information about changes to the specification and language discussions.

There's still a lot of work to be done, and I'm sure the Perl 6 developers are happy for any help they can get.

Thursday, January 21, 2010

"Your Unix Is Leaking Perl"

That has to be one of the weirdest statements I've read in, oh, at least fifteen minutes.[1]


(The image is a link to the original strip; if you've got javascript enabled, you can see this bonus strip by hovering over the burgundy red button below to the left.)


A huge thanks to Saturday Morning Breakfast Cereal for this piece of wisdom, but I'm afraid that Zach Weiner got it backwards when he thought that would be expensive.

May I suggest that when a computer "leaks Perl", it does so because the (hopefully brilliant) Perl programmer is contributing a lot to CPAN?

;)


Yes, I've been communicating with customers lately, how did you guess?

Thursday, January 14, 2010

feather.perl6.nl - a Sysadminish Tale

<@Juerd> frettled: Blog about the mess you found when
you first logged in on feather yesterday :)

Sure.

This will, incidentally, also explain why Trac is kindof unavailable now.

feather.perl6.nl is a Xen guest (a virtual machine, hereafter "VM") that's hosting several important services for the Perl 6 community. There's SVN web access, a Trac installation, and a bunch of other stuff I honestly don't know the half of.

Recently, the VM started running out of memory too often for comfort. What was going on? Juerd asked for help in tracking down the problem, as he didn't have the time to do so himself. And needing some distraction from work -- something to help me procrastinate -- I volunteered.

By now, you're probably banging your head on your keyboard in sympathy with me for saying something that may have been slightly less than brilliant. You know the feeling; Matt Trout reaches his right hand towards you, the world is suddenly in slow-motion, you see his hand closing in on you, his grin widening, and a voice saying "thhhhhaaaaannnnnkssss ffffooooorrr vooooluuunnnteeeerrriiiinnnnng", and you're basically up that creek with all the mud and dirt in it.

After handing over an SSH public key and getting sudo access (yeah, yeah, I know), I had a look anyway.

First, I went on a brief but wild goose chase, finding some error messages regarding ConsoleKit which appeared to be more frequent just before the server went out of memory, checked the Debian version (an unholy mix of Debian unstable and Debian experimental with lots of package updates pending someone's attention), and generally tried to get a feel of how the system was configured.

We already knew that Apache somehow might be responsible for gobbling up available memory, so my first action was to have a look at the last 100,000 lines of the Apache access log, using a simplistic log analysis script.

But which log? There were three Apache log directories to choose from. I (correctly) guessed that the one called simply /var/log/apache2 might be the interesting one, the others seemed to be legacy directories which should have been removed ages ago.

According to the script, there were 0 accesses in the last 100,000 lines.

Knowing the script, that was not so strange, because it makes a few assumptions regarding the log format, using a regexp belonging to the days before named captures and whatnot:
while (<>) {
if (/^(\S+) (\S+) - - \[[^\]]*\] \"(GET|POST) \S*
HTTP(|\/1\.[01])\" \d{3} (\d+) \"/) {
The regexp line has been split for the sake of the line width of this blog. There's nothing to be proud of here.

Anyway, I first had to remove the first capture; feather's logs weren't showing the virtualhost as the first column, and access types were most certainly not limited to only GET and POST:
frettled@feather:~$ sudo awk '{print $6}' /var/log/apache2/access.log|
sort -u
"CHECKOUT
"CONNECT
"DELETE
"GET
"HEAD
"MERGE
"MKACTIVITY
"OPTIONS
"POST
"PROPFIND
"PROPPATCH
"PUT
"REPORT
Right.

After straightening that up (and adding %v to the LogFormat specifications in the Apache config for future use), I got the following result:
Use of uninitialized value $size in addition (+)
at /usr/local/sbin/bandwidthips line 39, <> line 1002.
Use of uninitialized value $size in addition (+)
at /usr/local/sbin/bandwidthips line 40, <> line 1002.
Use of uninitialized value $size in addition (+)
at /usr/local/sbin/bandwidthips line 44, <> line 1002.
AAAARRGH! Idiot! Imbecile! Inept half-wit! Yep, I'd forgotten to renumber my captures. See, this is why Perl should be in version 5.10.1 or 6 when fiddling with those bloody annoying regexps.
frettled@feather:~$ sudo tail -100000 /var/log/apache2/access.log|
/usr/local/sbin/hitips|head
193.200.132.146: Bytes = 14329487 (3.44%), Hits = 51503 (51.82%)
66.249.71.2: Bytes = 132116084 (31.73%), Hits = 18111 (18.22%)
66.249.71.37: Bytes = 50846948 (12.21%), Hits = 6236 (6.27%)
93.158.149.31: Bytes = 54880221 (13.18%), Hits = 1894 (1.9%)
71.194.15.106: Bytes = 460200 (0.11%), Hits = 1894 (1.9%)
209.9.237.232: Bytes = 433388 (0.1%), Hits = 1686 (1.69%)
193.200.132.135: Bytes = 1726871 (0.41%), Hits = 1635 (1.64%)
193.200.132.142: Bytes = 429358 (0.1%), Hits = 1609 (1.61%)
208.115.111.246: Bytes = 8461415 (2.03%), Hits = 1238 (1.24%)
67.218.116.133: Bytes = 18945415 (4.55%), Hits = 1126 (1.13%)
So, uhm, around 52% of the hits come from feather3.perl6.nl, and nearly 25% from Google's indexer. Lovely.

Looking at the accesses from feather3, I quickly saw that they mostly had to do with svnweb.

Juerd had already stopped Apache, but someone -- I don't know who -- started it again at 12:00, probably anxious that SVN and such didn't work.

I then followed the running processes using the top command, updating each second (top d1), sorting by memory usage (typing M while top was running), hoping to catch some quickly growing processes.

Nopes. None, zilch, nada. Nothing that appeared horribly wrong. Sure, the apache2 processes used some memory (30-60 MB resident set, 50-100 virtual), but nothing appeared to be out of the ordinary. I changed the update frequency to each third second -- top sometimes uses an inordinate amount of CPU, depending on magic -- and waited. After a while, a couple of apache2 processes were using more CPU and memory than the others, around 60-90 MB resident. And they were growing. And according to lsof, they were active in the svnweb directory (and used a metric shitload of libraries). And after growing, they didn't release memory, they just kept on using it. But it wasn't enough to use up memory, there was still a bunch of free RAM.

So that was perhaps svnweb's fault, then?

Maybe.

But then my time ran out, and I had to drop the ball, leaving the top process running.

Five minutes later, the memory ran out again. It's just as if someone was waiting for me to go idle in order to produce the problem that I was looking for.

Sigh.



svnweb kindof remained the main suspect, until Juerd caught whatever was happening at the right time.

And catching what happens at the right time is bloody important.

Here's what he found, using Apache's server status:



Well, that's not svnweb. That's Trac. And the IP addresses belong to Google.



And that's spam, effectively creating a DoS or DDoS attack on our services as a side effect when search engines try to index the Trac webpages. It probably isn't intentional, but spammers just don't care.

So, what can we do to protect feather from suffering from such attacks in the future?

There's a lot that can be done. It takes effort. It takes time. It takes someone.

Here are a few suggestions on how to improve the robustness of the kind of services feather provides:
  • Add a captcha to the web form. The disadvantage is that this does not really save processing resources, but it probably should be done anyway.
  • Add an unnecessary and bogus input field to the web form, e.g. "Phone number". This input field should be hidden with CSS so that web browsers don't display it, and if someone submits anything with data with that field's name, then you can be nearly 100% certain it's spam from someone who's used a web scraper before automatically filling the form. Filter it out.
  • Change the webserver delegation architecture, so that each Apache process isn't loading tens of megabytes of libraries and keeping them in memory. Off-loading to shorter-living FastCGI daemons or similar solutions, or even sacrificing program startup speed by using CGI+suexec, etc., may be decent starting points.
  • Consider using a front-end proxy like Varnish to gloss over underlying nastiness.
  • Start with a new VM and migrate services to that one, gradually.
  • Document configuration choices and what each web service does/is there for, so that the next sysadmin coming along can make educated guesses quicker. :)
These tasks can rather easily be split into manageable one-person projects.

Does this sound interesting to you, or did I lose you at the third line of this blog entry?

Pop in on #perl6 on the freenode IRC network and say so.

Tuesday, January 5, 2010

Typing More Or Less

Not too long ago, there was a bit of minor cleanup in the Perl 6 specification regarding the use of whatever (*); there were some inconsistencies in how it behaved, depending on context.

The net result is that you now must use @arr[*-1] to get the last element, you cannot get away with simply using @arr[*].

Some may feel that this extra typing is bothersome, especially if you have a Unicode-friendly keyboard setup.

However, we can sneak our way past this problem by using a constant.

This also works with the current release of Rakudo, so it's not quite science fiction:
constant Ω = *-1;
Or, if you're feeling Cyrillic rather than Greek:
constant Ѡ = *-1;
Now we can substitute our nice constant for *-1 anywhere in the following code:
my @letters = 'a'..'z';
say '→'~@letters[*-1];
→z
Like so:
constant Ω = *-1;
my @letters = 'a'..'z';
say '→'~@letters[Ω];
→z
And, of course, you can do this with other things that are so tedious to type when you're dealing with maths:
constant π = pi;
say '→'~π
→3.14159265358979