WordPress memcached 3.0.0

Some software is so stable that it becomes stagnant. Yesterday’s update of the WordPress object cache drop-in for memcached flings it from both categories, back into active development where it is sure to capture the attention of WordPress site administrators around the world.

So much for drama and spin. All that really happened was this: I pushed a major-version update that finally allows `wp_cache_flush()` to work for WordPress sites using memcached. You probably shouldn’t care at all; you had better click away to a video of a suburban father longboarding with a short-legged dog.

In case you do care, it can only be because you belong to the elite club of techies who administer a WordPress site with the help of memcached. Our records on this population are scarce. By one estimate–surely a miscalculation–there are fewer than ten installations of this software in the world. You may call it hubris but I suppose the number might stretch well into two-digit territory.

What you few need to know is this: upgrading to 3.0.0 will instantly flush your entire cache. This will happen because the key format has changed. I didn’t bother writing any code to gradually migrate keys, nor do I offer any other strategy mitigate this potentially catastrophic effect. You should be keen enough to handle it.

Beyond that, you can look forward to fewer problems along the lines of WordPress getting stuck in a database upgrade loop. This is when you’ve upgraded your database but WordPress keeps insisting that you haven’t, locking you out of wp-admin. That’s what happens when `wp_cache_flush()` has no effect. That’s just how it was for multisite installations because memcached’s own flushing mechanism was too blunt for such use.

How it works is not too hard to invent. Cache keys are automatically prefixed with a number that pseudo-uniquely represents the current “flush count” of either the current site or the global cache. Flushing is accomplished by incrementing that counter so that stale entries are hidden to subsequent accesses. The counters are stored in memcached so they exhibit the same performance characteristics as the cache entries they marshal.

2016 is not the first time we have tried this. Eight or so years ago, the same strategy was attempted on what was and is the world’s largest WordPress installation. Sensing trouble, we backed away from the high road and skirted the problem by inserting proprietary code in our copy of WordPress. If you’re the type that wants to dive into the gory details of these hacks, we have a special place for you.

We revisit the high road now because time has taught us to lean into trouble. We cherish our scars and we regret having sustained so few of them over the years. Second, we want future projects to hold tighter to the ethos of open source software and pushing improvements upstream for all to enjoy.

Like all versions of WordPress and this drop-in extension, 3.0.0 is free of charge. It will cost you one or two cache reads every time WordPress generates a page. If you find this expense immodest then I hope you will contact me about your use case.

I hope 3.0.0 proves stable enough to vanish back into obscurity. If it gives you trouble, come find me and we can make 3.0.1 together.

Thanks to Peter Westwood for reviewing the code and suggesting an improvement.

How to tail a log with live server clock

At work I have to watch my server’s error log. Good old tail -F /path/to/log runs over SSH all day, every day. Each entry is timestamped. Sometimes those timestamps give me trouble. The age of a timestamp is found by subtracting it from the current time. If I need to know whether the last error occurred 1 minute ago or 61 minutes ago I have to contend with:

  • timestamps in UTC vs. local clock in CST
  • timestamps in 24h vs. local clock in 12h
  • terminal window on second screen vs. clock on main screen
  • daylight savings vs. non-crazy time
  • being at home vs. traveling in other time zones

Finding the age of a timestamp should be simpler than that! So I put a real-time UTC clock in the most convenient place I could find: on the blank line where the next log entry will be written. It refreshes itself every second. Log entries overwrite it and then it reappears again on the new blank line.

The clock on the next line refreshes itself.
The clock on the next line refreshes itself.

Now I can find the age of the last entry without thinking about time zones or daylight savings, without turning my head to check the clock, and without even holding any numbers in my head. Eyeball math. Success!

#!/bin/bash
ssh $1 $(cat <<COMMAND
    while true; do
        echo -ne \`date +"[%d-%b-%Y %H:%M:%S UTC]"\` "\r";
        sleep 1;
    done &
    tail -Fn`tput lines` $2
COMMAND)
echo

If you save this script as st in your path and chmod +x it you can invoke it with st example.com /var/log/file (provided you can ssh example.com and read the file).

I used a few small tricks to compose this solution.

  • the while loop runs in the background (done &)
  • echo -n prints its arguments without a line feed
  • echo -e interprets escape sequences, converting "\r" into a carriage return
  • bonus: `tput lines` passes the local terminal height to tail
  • the final echo gives your prompt a fresh line when you exit with ^C

After SSH connects, the loop starts sending [timestamp]\r to the terminal every second. The carriage return moves the insertion point back to the start of the line without moving it down to the next line. That explains the location of the highlighted character in the image above.

Then tail fills your terminal window with log entries and continues printing new entries as they appear, overwriting the clock. No space wasted, no information lost.

Caveats:

  • log entries must be timestamped and must end in a newline
  • date format is up to you
  • n`tput lines` is optional
  • the clock might draw over log data

That last point is theoretical. It hasn’t been an issue in the two months since I started using this. I also tried to force the clock to overwrite the tail output under abnormal conditions. The only way I could do it was by manually appending to the file without a trailing newline. I guess it depends on the size of the log entries and how they are written. Either way, it’s only terminal output. The log file itself is unmodified.

The script I posted above isn’t exactly what I have been using. It was modified for clarity and generality. I added positional parameters and $(cat <<heredoc) to get clean newlines without having to escape too much. Since I only use this utility to tail one file on one host, the original looks more like this one-liner:

ssh example.com 'while true; do echo -ne `date +"[%d-%b-%Y %H:%M:%S UTC]"`"\r"; sleep 1; done & tail -Fn'`tput lines`' /var/log/file'; echo