Some ISP doesn't let user to make LOCK on tables (I'm thinking at free.fr a famous french free ISP).
This patch provide another method to lock tables using SELECT ... FOR UPDATE

Comments

chx’s picture

Hm , tostinni is this applicable for MyISAM tables? I thought select for update is for InnoDB.

tostinni’s picture

Well, MySQL doc doesn't specify that it's restricted to MyISAM tables type, in fact I try this in a DB I got at free.fr which restrict tables types to MyISAM and it worked.

So I guess it's fine ;)

dries’s picture

SELECT ... FOR UPDATE uses row-level locking which requires MySQL 4 as far as I know. The syntax is ANSI SQL though. Are you using MySQL 3 or MySQL 4?

dries’s picture

I wrote a mail to drupal-devel about making MySQL 4 a requirement. If we agree to drop support for MySQL 3, the proposed patch might improve performance too (although it will not be noticable).

menesis’s picture

StatusFileSize
new702 bytes

From MySQL Reference Manual, SELECT Syntax:

If you use FOR UPDATE on a storage engine that uses page or row locks, rows examined by the query are write-locked until the end of the current transaction.

Meaning FOR UPDATE clause is allowed on any engine, but it only works on InnoDB; MyISAM just ignores that, and no locking occurs.

I found a useful tip in Locking Reads SELECT ... FOR UPDATE page:

In MySQL, the specific task of generating a unique identifier actually can be accomplished using only a single access to the table:

UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 1);
SELECT LAST_INSERT_ID();

The SELECT statement merely retrieves the identifier information (specific to the current connection). It does not access any table.

Tried to modify db_next_id(), diff attached, but not sure how to test if that works. Just an idea.

menesis’s picture

StatusFileSize
new1.11 KB

misread my own quote, missed LAST_INSERT_ID in the query. Updated diff.

tostinni’s picture

Ok, sorry, I thought that MySQL doc would be more explicit regarding ROW locks.
As I didn't encounter errors with MySQL 3, I thought lock just apply correctly.

BTW, I read the doc and had seen the LAST_INSERT_ID that menesis proposed, but as it didn't make any lock, I thought it wouldn't be an acceptable way to handle the db_next_id integrity.

killes@www.drop.org’s picture

LAST_INSERT_ID only works with auto_incremented columns.

moshe weitzman’s picture

well, as a separate task we might consider throwing out our sequqnces implementation and just using DB provided seqences. Both pgsql and mysql provide these. mssql does too in case we ever revive support for it. Further, PHP 5.1 brings us PDO (a native DB access layer) that handles sequences automatically: http://www.php.net/manual/en/ref.pdo.php

tostinni’s picture

Further, PHP 5.1 brings us PDO (a native DB access layer) that handles sequences automatically: http://www.php.net/manual/en/ref.pdo.php

This look promising, I hope we can see a support for Oracle DB one day, and I will help to support this.
But let's focus on the main thread ;)

I wasn't at the birth of Drupal, and I wonder why we use db_next_id sequence for MySQL if it exists since version 3 ? (also see this thread).
So I agree about abandonning this, unless there's a big compatibility reason.

kbahey’s picture

I agree with Moshe that we should use the database's autoincrement feature, and not our own sequences.

As he said, the two engines we support already do it, as well as the potential third engine as well.

I disagree somewhat with the PDO thing, since it is PHP5 only, and hence not suitable for the time being. In the future, maybe, but not now.

allie micka’s picture

LOCK's don't play well with multi-master replication (which we're using). MySQL 5 has support for safe auto_increment.

I would be in support of having every table use its own auto_increment, but here's what we have done for now:

function db_next_id($name) {
  $name = db_prefix_tables($name);
  db_query("INSERT INTO {sequences} (name) VALUES ('%s')", $name);
  $id = db_result(db_query('SELECT last_insert_id()'));
  db_query("DELETE FROM {sequences} WHERE name='%s' AND id < %d", $name, $id);
  return $id;
}

AND...

ALTER TABLE sequences DROP PRIMARY KEY;
ALTER TABLE sequences ADD PRIMARY KEY (name, id);
ALTER TABLE sequences MODIFY COLUMN id INT AUTO_INCREMENT;
magico’s picture

Version: 4.6.0 » x.y.z
chx’s picture

Version: x.y.z » 6.x-dev
Status: Active » Closed (duplicate)