Confirmed: Windows Azure downtime caused by leap-day bug
blogs.msdn.com
blogs.msdn.com
http://aws.amazon.com/message/65648/
(Scroll to last paragraph.)
We will post an update on this situation, including details on the root cause analysis at the end of this incident.
I think that's fair enough (assuming they don't just quietly forget about this last part).Everything is PR. Even if this was indeed a very thorough and technical rundown of the issue, it would still exist only because of PR.
First, the fact that the same exact type of bug had been known in 1999 and yet they either failed to fix it in the newer code base or they reimplemented the exact same bug in new code.
Second, almost certainly the reason that these bugs weren't caught earlier is because it's unusual for Windows to have such long uptime (50 days for Win 9x is impressive, and over a year for Windows server equally so). More so, almost certainly the average user has such low expectations of windows reliability that if they see the system become unstable or slow after a long period of uptime they will as a rule merely reboot the system rather than investigate.
Edit: a thought occurs to me. Perhaps the "fix" for the older problem was to simply change from using milliseconds since last boot for tcp/ip socket age to using hundredths of a second. I really, really hope that wasn't the case.
$ date -d "Feb 28 2012 17:45 PST" -u
Wed Feb 29 01:45:00 UTC 2012
Does that mean it took them nearly two hours to spot the problem? Or are they not running on UTC?I don't recall any of this occurring in 2008 or 2004.
It's not just Microsoft that does stuff like this either. Apple regularly messes up iPhone alarms during daylight savings.
Also divisible by 100 => not leap year unless also divisible by 400.
It's really not that complicated.
[edit: Oops. I messed it up. Irony. Fixed now.]
http://en.wikipedia.org/wiki/Leap_year
What baffles me is did they really have to rewrite that again somewhere else? Don't they have libraries in whatever language they are using with something to do the date calculations they need?
I think unless you're messing with non-Gregorian calendars, this is a solved problem. Am I missing something?
This is only the beginning, there are so many possible issues related to an edge case like this, while it might be a "solved problem" that doesn't mean it's something developers are thinking about every day. And don't even get me started on daylight savings time...
Google has an interesting post on how they handled the Leap Second in 2008: http://googleblog.blogspot.com/2011/09/time-technology-and-l...
For example, the system call gettimeofday(2) does only return the seconds since Jan 1, 1970 (the 'epoch'), the time zone and the daylight saving time correction. No day, no month, no year. For this, you have to call some other function, eg. libc' localtime(3).
libc's time(3) function says it returns the number of seconds since the epoch, but it ignores leap seconds, so it actually does not return the number of seconds since the epoch (since there have been several leap seconds since the epoch).
Even if you use localtime(3) to get the actual wall clock hour and minutes, you are left on your own from there. Want to have a time point two hours from now? Do your own math, but watch out for the end of the day, which might also be the end of the month and/or the end of the year. One month from now? Do your own math, but watch out for months that have less days than your current month.
You may want to resort to do calculations only in seconds since the epoch, but how many seconds are in a month? Depends on the month (and the year as we've just learned!). In a year? Depends on the year (Is it a leap year? Was / will be there a leap second? Do you have to care about leap seconds?).
I just picked the C language because it is so prevalent. Other languages have their own issues or inherit them from C. In Python, for example, there is a timedelta object, but it can only handle days, seconds, and microseconds, so you still cannot calculate the date one month from now or one year ago.
I find it unbelievably funny that it's 2012 and we still have to deal with this 'solved problem'. Turns out, it is not solved at all.
It returns the number of actual seconds that have elapsed since the epoch, the only way to do this is to ignore leap seconds. When leap seconds occur, they don't actually exist, they just change the offset to keep things in sync. Every second the time(3) function returns exists uniquely and none are skipped, there are no ambiguous values, which you can't say if leap seconds were not ignored.
Besides, my point was that I think time is such an essential data point, it should be handled directly by the language without the need to look for a library. Like sin() is directly accessible in every non-toy language.
In other projects I've used clock_monotonic (POSIX, but needs a Python module or ctypes until the next Python 3 release), and either dateutil (if I need to do more advanced calendar math) or pytz (if I just need a timezone database).
I've never worked on a product where timekeeping was essential, but if I did, I'd probably use libtai[1], by DJB.
>>> t = list(time.localtime()); t[2] -= 1; t[3:6] = [8,0,0]; print time.ctime(time.mktime(t))
Wed Feb 29 08:00:00 2012
That correctly handled the leap day and the change in month number -- the 0th day of March became the last day of February.Give the 1st of the month, 11 months from now:
>>> t = list(time.localtime()); t[1] += 11; t[2:6] = [1,8,0,0]; print time.ctime(time.mktime(t))
Fri Feb 1 08:00:00 2013
That also converted the 14th month of 2012 into the 2nd month of 2013. >>> t = list(time.localtime()); t[2] -= 1; t[3:6] = [8,0,0]; print time.ctime(time.mktime(t))
Wed Feb 29 08:00:00 2012
>>> t[1] -= 1;
>>> time.ctime(time.mktime(t))
'Tue Jan 31 08:00:00 2012'
So if you have a `t` that is Feb 29, one month ago is Jan 31 or Feb 29, depending on how `t` was constructed.(x) Edit: I meant, it's good to know about the time module in Python, not that you know Python...
The second time you have, is 0th February. So that underflows back to the previous day, Jan 31st -- the day before February 1st.
Of course, internally, all is correct, but for the user, things may behave strangely.
So I don't see how libc or other low-level libraries are relevant here. My assumption implies that you're using some library with support for dates. I'm not even assuming that you're Microsoft, though that helps.
(Note that this has little to do with leap seconds. There are astronomers that might care about the details, but for most of us it's enough to think of a leap second as a "long second".)
So you must already have a library that provides you with the adequate abstractions.
Given that it failed on Feb 29, either the library is weak, used wrongly, or no such library had been in use. Instead, the code may have assumed that every February has 28 days or it calculated the leap year wrongly. In either case, I can imagine that code that assumes that Feburary has 28 days may go havoc on the 29th. For example, before midnight you might want to schedule some important task two hours from now, do calculations based on the number of seconds in two hours and calculate the task to happen on March 1st instead of February 29th.I think the issue arises because even though time is such an important (and difficult to handle) data point, there is hardly any language support or the libraries are weak.
http://www.computerworld.com/s/article/9124638/Zune_chokes_o...
Money quote: "Microsoft says it will issue a bug fix for the device so that this problem won't occur again in 2012, the next leap year."