Avoiding future character wipes

by Winston on November 12, 2009

With v1.77 of Modular Combat, we will be moving our characters to a whole new database system. This will require a character wipe, but we’ve got a whole bunch of new character-related features to soften the blow.

This article is about our strategy for avoiding character wipes in the future. We can’t make a cast-iron guarantee that we’ll never require servers to have to wipe characters ever again, but we’re pretty happy with our new system, so prospects looks promising.

So what is the new system?

Well, we’ve moved our characters into a single sqlite database. Compared to the “millions of keyvalues files” system we had before, this is a breeze to manage. It will also let us do character comparison things across teh whole database, like leaderboards for who has the most kills, the most time played, the highest kills per minute, etc.

But what about the next new feature we add to the system? If we decide (stupid example) that we want to count the number of footsteps every character has ever made, and that we have to get this in regardless of the costs, we’ll no longer have to wipe an old database that doesn’t track footstep count, and replace it with a new one. Instead, we’ve added a simple “version number” to our databases, and we’re including in our code every database change script that is needed to move between any old version of the database and the latest version, automatically.

Essentially, the “latest version” value is hardcoded into our server dll, and when starting up, the code checks the database version against the code version, if they don’t match then a switch statement is performd, something like the pseudocode that follows:

if ( databaseVersion != codeVersion )
{
    switch ( databaseVersion )
    {
    case 1:
        ... // upgrade v1 to v2
    case 2:
        ... // upgrade v2 to v3
    }
    // database is now up to date with the latest version
    databaseVersion = codeVersion;
}

This assumes the following hypothetical scenario:
Version 1 of our new database is released. Then comes version 2, in which we add headshot tracking, and then version 3, where we add tracking for the total number of footsteps characters have taken. Version 3 is the latest version.

  • Consider first starting up a server whose database is of the latest version, version 3. As the database version matches the code “latest version,” there’s nothing special we need to do; the server can start as normal.
  • Now imagine a server with a version 2 database, having just upgraded the code to version 3. The “upgrade from v2 to v3″ code will be run (adding footstep tracking), and then the database will be marked as being v3, as it is up to date.
  • Lastly, consider a server that never got around to updating from v1 to v2, and now v3 is out. This server still doesn’t need to worry about losing character data, as the switch statement can handle upgrading from any previous version to the latest version, as it has no break statements at the end of each case section. Firstly, the database will be updated from v1 to v2, and then (immediately) the code to update from v2 to v3 will be run. Now this database is also fully upgraded to v3, and no matter how many upgrades are needed (v1 to v52891, say), there is still a straightforward linear chain of upgrade commands. Furthermore, having all these extra upgrade commands don’t slow the server down any or get in the way, as they’re bypassed completely when running an up-to-date server.

This is an extremely simple solution to updating any previous version of a database to the latest version. It may not be particularly applicable to vast commercial databases with hundreds or thousands of tables, but for a database of the size an mod or indie game team is likely to produce, it lives up to the old mantra of Keep It Simple, Stupid, without abandoning users of older versions.

Leave a Comment

Previous post: Bringing a mod to a new engine