Point In Time Recovery From Backup using PostgreSQL Continuous Archving

2012-03-09 13:55:44 -0500

Last year, around this time we, published details of how we setup PostgresSQL backups using Continuous Archiving. This technique involves continuous WAL archives combined with a daily "baseline" backup script:

Backups are only half the picture, though; the ability to easily restore data is just as critical. Unfortunately, the recovery process, as documented, can be a bit complex. Here is an distilled, exact step-by-step procedure we use to recover from backup.


This assumes that hot-backups are enabled in postgres. Ensure the following are setup in postgresql.conf on the box where the backups are located

wal_level = hot_standby                 # minimal, archive, or hot_standby
archive_mode = on               # allows archiving to be done
archive_command = 'cp -n %p /backup/postgresql/%f'

Understanding the Backup Folder Structures

The PostgreSQL WAL-based backup approach is structured on a base backup, and then a set of transaction logs that can be applied on it.

Via the backup script, daily baselines are stored in the PostgreSQL backup folder, /backup/pg_backups, in folders like this:

drwxr-xr-x    2 106      113           4096 Aug 24 05:15 2011-08-23.09:00:01
drwxr-xr-x    2 106      113           4096 Aug 25 05:16 2011-08-24.09:00:01
drwxr-xr-x    2 106      113           4096 Aug 26 05:16 2011-08-25.09:00:01
drwxr-xr-x    2 106      113           4096 Aug 27 05:16 2011-08-26.09:00:01
drwxr-xr-x    2 106      113           4096 Aug 27 05:19 2011-08-27.09:00:01

In this case, the folder is named after the current date and the base backup. For example, the folder named 2011-08-25.09:00:01 would contain the base backup from 9 AM UTC, along with the WAL log files archived between 2011-08-25.09:00:01 and 2011-08-26.09:00:01. Thus, to restore to any point in that time you should use the files from that backup folder:

  1. base.tar.bz2 - full backup of the postgresql data folder (i.e. /var/lib/postgresql/9.x/main)
  2. pit-wal.tar.bz2 - point in time logs captured for transactions active while the base snapshot was being taken
  3. full-wal.tar.bz2 - the archive of all transaction logs present between the base backup and the following day's base backup

In the case of the current date, the folder corresponding to today's date will contain the base backup (base.tar.bz2) and the point in time logs pit-wal.tar.bz2. However, the full-wal.tar.bz2 file will not be present because the day's logs have not been archived yet. Instead, the current day's archive logs are stored in the archive logs directory, /backup/postgresql.

There are two options for data restoration:

  1. restore up to the last backup point in the current date
  2. restore to a previous day's backups

The process between these two is basically the same, the only difference is whether the WAL logs are extracted from the full-wal.tar.bz2 or taken from /backup/postgresql

Step 1. Copy data backup

Copy all the files from the appropriate backup folder to your home directory. The following assumes you have the archive files in the home directory of ~postgres (substitute as necessary).

In order to perform the restore, we'll create a temporary directory in which to stage the files.

cd ~postgres
mkdir restore
cd restore

Step 2. Extract base data and PIT logs

tar xjf ~postgres/base.tar.bz2
tar xjf ~postgres/pit-wal.tar.bz2
cd backup/postgresql

Step 3. Extract WAL data

  • If you are restoring from a previous day
    tar xjf ~postgres/full-wal.tar.bz2
  • If you are restoring from the current day
    cp /path/to/today/backup/postgresql/* .

Step 4. Shutdown Postgres

# shutdown postgres
sudo su -
service postgresql stop

Step 4. Restore main data directory

Start by moving into the base version directory. Move the existing main folder out of the way, then move the restored base back into place

cd /var/lib/postgresql/9.x/
mv main main.bak
mv ~postgres/restore/var/lib/postgresql/9.x/main main
cd main

Step 5. Create a recovery.conf

Now that the base backup is restored, you must to tell PostgreSQL how to apply the recovery procedure. First, create file called recovery.conf in the data directory, /var/lib/postgresql/9.x/main/recovery.conf. The contents should minimally include the following line, adjusted to the location of the WAL files.

restore_command = 'cp /home/postgres/restore/backup/postgresql/%f %p'

If you only want to apply transactions up to a specific point in time, for instance to recover to the middle of a specific day, add the recovery_target_time (note the time stamp will be relative to UTC):

recovery_target_time = '2011-08-27 04:00:00.0'

Step 6. Start PostgreSQL

service postgresql start

When PostgreSQL has finished restoring the files the recovery.conf file will be renamed to recovery.done.

Note: Information and additional details from:


SQLCipher in The Busy Coder's Guide to Advanced Android Development

2012-03-06 16:10:18 -0500

The latest version of the Busy Coder's Guide to Advanced Android Development, published by CommonsWare, has recently been released. Chapter 21, Advanced Databases, is dedicated to database techniques like encryption. SQLCipher for Android is featured prominently along with a tutorial and discussion of proper integration techniques.

If you've been looking for a good book on advanced Android development topics that includes SQLCipher database encryption you should definitely check it out!

PRAGMA cipher_default_use_hmac = OFF;

2012-03-01 10:59:03 -0500

We needed a new PRAGMA! These things happen.

With the release of SQLCipher 2.0, a PRAGMA was added (cipher_use_hmac) which disabled the new per-page HMAC protection feature before opening a database, so that a developer wishing to run SQLCipher 2.0 against a 1.x database could do so. This was important to us because we wanted to provide an easy way for developers to migrate to the new database format. Generally speaking, you'd want to do something like this:

  1. Open the legacy database, set your key
  2. Call PRAGMA cipher_use_hmac = OFF; before opening the legacy database
  3. ATTACH a new, empty database, which will be encrypted by default and have HMAC on by default
  4. Copy your database into the attached database using sqlcipher_export()

That scenario looks about like this on the command line:

$> ./sqlite3 my-legacy-encrypted.db
sqlite> PRAGMA key = 's3cr37';
sqlite> PRAGMA cipher_use_hmac = OFF;
sqlite> ATTACH DATABASE 'new-sqlcipher2.db' AS newdb;
sqlite> SELECT sqlcipher_export('newdb');
sqlite> DETACH DATABASE newdb;

But there are other scenarios, ones in which we really needed to be able to ATTACH one legacy database to another (e.g. data replication). Even though we'd have called PRAGMA cipher_use_hmac = OFF; when opening the first database, the ATTACH operation assumed the new default format, and would report back "database is encrypted or is not a database."

We didn't wish to modify the ATTACH command, and we didn't want to change the behavior of cipher_use_hmac, as the latter's behavior is necessary for developers who wish to migrate and upgrade their databases. Instead, Stephen came up with a new PRAGMA, cipher_default_use_hmac, which is a globally applied setting in SQLCipher, allowing you to turn HMAC protection on and off before you open or ATTACH another encrypted database, so you only need to bother with one setting in your app. Here's an example (where custom_data_replicator() is a made-up function):

$> ./sqlite3 my-legacy-encrypted.db
sqlite> PRAGMA cipher_default_use_hmac = OFF;
sqlite> PRAGMA key = 's3cr37';
sqlite> ATTACH DATABASE 'remote.db' AS remote;
sqlite> SELECT custom_data_replicator('remote');
sqlite> DETACH DATABASE remote;

Pretty dang handy and available now on the master branch—stay tuned to the mailing list for details on new tags and release numbers. You can see the changes here along with updated unit tests.

Meanwhile, I've made some mods to SQLCipherManager to support this specific scenario. Setting the property useHMACPageProtection causes the new global PRAGMA to be called before a database is opened, rather than the older cipher_use_hmac. This allows you to attach 1.x or 2.x databases at will, by changing the setting when you need to, like so:

self.dbManager = [SQLCipherManager sharedManager];
[self.dbManager setUseHMACPageProtection:NO];
@try {
  [self.dbManager execute:
    [NSString stringWithFormat: @"ATTACH DATABASE '%@' AS remote;", [replicaURL path]];
  [self.dbManager beginTransaction];
  [self.dbManager execute:@"SELECT custom_data_replicator('remote');"];
  [self.dbManager commitTransaction];
  [self.dbManager execute:@"DETACH DATABASE remote;"];
@catch (NSException *exception) {
  // SQLCipher's execute: command now provides handy exceptions!
  // For traditional error handling, use execute:error: instead.
  NSLog(@"Command failed: %@", [exception reason]);

Strip for Android Coming Soon

2012-03-01 09:36:52 -0500

One of the most frequent requests we receive for Strip is support for Android. Android is one of the largest mobile platforms next to iOS. To support this, we first needed to port SQLCipher onto the Android platform. SQLCipher is our open source extension to SQLite that allows for transparent 256-bit AES encryption of database files. We began last year working in conjunction with The Guardian Project on this process. This has required bundling a custom build of the ICU project to allow portability across Android versions 2.1 through 4.0.3 (Ice Cream Sandwich). You can read more on integrating SQLCipher for Android here. With this out of the way, we've been focusing on the application development work and are nearing completion for an initial delivery.

Unlike the iOS platform, where users upgrade to the lastest iOS release quickly, the Android platform is more fragmented due to manufacturers playing a role in the update distribution process - more about this here. That said, we have been working to target Android versions 2.1 and up for Strip on Android - targeting the majority of users. We have also tried to maintain a consistent user experience between the iOS application and Android where it makes sense. An example of where the iOS and Android platforms differ is in their drag and drop support. iOS provides a native drag and drop interaction within their UITableView, requiring you to set an editing mode and handle a few events. On Android however, support was added in 3.0 for drag and drop, prior to that you are left with the implementation details. If you want to be notified when we release Strip for Android, sign up here. We are very excited about adding support for the Android platform and hope you are as well. We will leave you with a screenshot of the upcoming Strip for Android. Thanks!

Strip for Android

Intro to iPad, iPhone, & iOS Application Development at Cowerks

2012-02-27 18:07:54 -0500

Bret Morgan of Cowerks, a good friend of Zetetic, is organizing a cooperative learning program in late April designed to give participants a crash course in iPad/iPhone development.

The approach is unique; instead of a traditional "teacher leads, students learn" class model, participants will work together as a cooperative development group. Following the first half of the Stanford University CS193P iPhoneApplication Development curriculum, the goal is to cover a wide range of iOS topics in just 8 weeks of sessions:

  • Walkthrough of iOS 5
  • Objective-C
  • Views
  • Autorotation, Protocols, & Gestures
  • View Controllers
  • UIToolbar and iPad Apps
  • Controller Lifecycle & Image/Scroll/WebViews
  • Table Views

With the course materials and group as a guide, attendees will work both collaboratively and on their own time to learn Objective-C and the relevant SDKs.

It's a really neat concept, so if you're in the NJ area and you've been waiting for a reason to learn iOS development, this could be a great opportunity. Classes start on April 23rd, and registration is open now with early-bird discounts at http://cowerks-ios.eventbrite.com.