[development] A gotcha with auto-increment and MySQL

Darrel O'Pry dopry at thing.net
Thu May 3 23:29:07 UTC 2007


On Thu, 2007-05-03 at 12:25 -0400, Barry Jaspan wrote:
> The most recent thread on using auto-incrementing columns in Drupal
> seems to have led to the decision that it is okay to use them
> (acknowledging that both our mysql and pgsql tables already do use
> them), and the upcoming database schema data structure supports them.
> However, while in my waking-up haze this morning, out of nowhere I
> realized one of the reasons they were probably previously avoided.
> 
> On an auto-incrementing column, a race condition exists if
> db_next_id() is sometimes used and sometimes not used.  The problem is
> that while db_next_id() is atomic it does not alter MySQL's idea of
> the next id to assign.  Suppose at T0 the maximum nid in the node
> table is 10 and the sequences table reflects that.  At T1, one Drupal
> process calls db_next_id('{node}_nid').  The sequences table is
> atomically updated to 11 and the caller gets 11.  At T2, a second
> Drupal process inserts a new row into the node table without providing
> a nid; since the maximum nid is 10, the new row is assigned nid 11.
> At T3, the first process tries to insert a row using the nid 11 it got
> from db_next_id() and fails.
> 
> This problem does not occur with pgsql because the db_next_id() and
> the auto-incrementing column both use the same underlying 'sequence'
> object.
> 
> I see two ways to solve this problem:
> 
> 1.  Disallow auto-incrementing columns everywhere in Drupal.  Note
> that they are used on numerous core tables both with mysql and pgsql.
> To remove them, we would have to verify that every insert into a table
> uses db_next_id() to generate the new id.
> 
> 2.  Just don't use db_next_id() and auto-increment on the same
> columns, ever.  We could just declare this a bug and fix it when
> discovered.  However, now that we (will soon) have a database schema,
> we could also make db_next_id() actively warn about it:
> 
> function db_next_id($name) {
>   list($table, $col) = preg_split_table_and_column_name($name);
>   $schema = drupal_get_schema();
>   if ($schema[$table]['cols'][$col]['type'] == 'serial') {
>     // log an error here
>   }
> 
>   // rest of db_next_id() here
> }
> 
> Thoughts?
> 
> Barry

I'd say 2. I think best practice is to decide if you want to use
auto_increment or sequences for your table and stick with one. 

However, just because both Postgres has something auto_increment like
doesn't mean they're equivalent. Auto increment is bad for anyone
tinkering with multi-master environments. 

I've seen the light. I'll take my ticket from db_next_id and wait in the
queue.

.darrel.



More information about the development mailing list