Generating Even and Odd PostgreSQL Databases for Replication

I was recently faced with a problem of replicating two PostgreSQL databases with bucardo. The replication was to be in a master-master fashion so that the databases could be updated on both ends. Although this task can easily be handled by bucardo it requires that the two different systems generate completely different sets of primary keys. According to the Bucardo website (http://bucardo.org/wiki/Bucardo/Sequences) there are three ways of achieving this difference. Their approaches were:

If you are using a swap sync, the best practice is to *not* replicate sequences, but to make sure that they are different on both sides, such that an insert on database A will never conflict with an insert on database B. There are three general ways to do this:

  1. Use interleaving sequences. On database A, define the sequence as START WITH 1 INCREMENT BY 2. On database B, define the sequence as START WITH 2 INCREMENT BY 2. Thus, the two sequences will never have the same value.
  2. Use different ranges. For example, database A would use a sequence of START WITH 1, while database B uses START WITH 100000000. This is not foolproof, as A can eventually catch up with B, although you can define A as MAXVALUE 99999999.
  3. Use a common sequence. This relies on one or both of the databases using a function that makes a call to an external sequence

After reading this I decided to go by the first approach so I wrote a script to alter the sequences.


// Add the sequences you dont want affected here. The schema doesn't
// really matter.
$exclude = array(
    'client_code_seq',
    'jv_number_seq',
    'pv_number_seq',
);

for ($i = 1; $i < $argc; $i++)
{
    if(substr($argv[$i], 0, 2) == "--")
    {
        $parameter = substr($argv[$i], 2, strlen($argv[$i]) - 2);
        $i++;
        $$parameter = $argv[$i];
    }
    else
    {
        $tables[] = $argv[$i];
    }
}

$conn = pg_connect("host=$host port=5432 dbname=$db user=$user password=$password");

pg_query($conn,"BEGIN");
$sequences_result = pg_query($conn, "SELECT * FROM information_schema.sequences");
$sequences = array();
while($sequence = pg_fetch_assoc($sequences_result))
{
    if(array_search($sequence['sequence_name'], $exclude) !== false)
    {
        echo "Skipping " . $sequence['sequence_schema'] . '.' . $sequence['sequence_name'] . "\n";
        continue;
    }
    $sequence = $sequence['sequence_schema'] . '.' . $sequence['sequence_name'];
    $value = pg_query($conn, "SELECT last_value from $sequence");
    $value = pg_fetch_assoc($value);

    pg_query($conn, "ALTER SEQUENCE $sequence INCREMENT BY 2");

    if($value["last_value"] % 2 == 0 && $mode == 'odd')
    {
        pg_query($conn, "ALTER SEQUENCE $sequence RESTART WITH " . ($value['last_value'] + 1));
    }
    elseif(($value["last_value"] % 2 == 1 || $value["last_value"] == 1) && $mode == 'even')
    {
        pg_query($conn, "ALTER SEQUENCE $sequence RESTART WITH " . ($value['last_value'] + 1));
    }
}
pg_query($conn,"COMMIT");

This script takes five required parameters. The parameters are not validated so if it is wrongly specified the consequences are unknown. PLEASE BE CAREFUL! The parameters are:

  1. The hostname
  2. The username
  3. The password
  4. The database name
  5. The mode of the change (even or odd)

An example usage could be

php update_sequences.php --host db1.accra.srv --user postgres --password somepass --db appcore --mode even

Hope that helps. Happy Programming!

 

Advertisement

About James Ekow Abaka Ainooson

Well I am just an average dude who believes no single person can change the world. It would take the collective effort of everybody to make this world a better place. But just think, what would this world be like if there were no evil ... Booooooring! I was born in Accra and I have spent all my life in Accra. I had my education in Datus, Accra Academy and the University of Ghana. I also had an opportunity to spend a semester at the University of Guelph in Canada. Trust me I really liked it there. I met some of the greatest people you can ever meet. Currently I work as a software developer for NTHC Limited.
This entry was posted in How To do Stuff, PHP and tagged , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s