Benjamin Pflugmann wrote: >>>[...] Which table >>>type (MyISAM/InnoDB/BDB) do you use? Do you intend to use transactions >>>or not? >>> >>I am using BDB tables, and I am making use of transactions. >> >Okay, than that is the reason for the deadlocks and it is to be >expected, as far as I understand (as writers are involved): >http://www.mysql.com/doc/B/D/BDB_characteristics.html > >BDB tables use optimistic locking, i.e. it is assumed that you are >lucky, and no one else will need the same locks as you do. If you >conflict with other locks, one of your will gets an deadlock error. >(From http://www.sleepycat.com/docs/ref/transapp/put.html - did not >find an explanation in the MySQL manual :-( ) > This reference is very useful, actually. If I modify my test program to detect the deadlock as shown in the example in your reference (see code below) then two instances of the program now seem to run quite happily together, with one or the other occasionally going through phases like
[...] i = 396 i = 397 Retrying 397 i = 397 Retrying 397 i = 397 i = 398 [...] and then continuing successfully. (Obviously I need an upper limit on the number of retries.) ------------------------------ use strict; use warnings; use DBI; my $dbh = DBI->connect('dbi:mysql:test', 'root', '', {AutoCommit => 0, PrintError => 0, RaiseError => 1}); for (my $i = 0; ; $i++) { print "i = $i\n"; # "Catch" any errors in the do() or commit()... eval { $dbh->do("INSERT INTO x (id) VALUES ($i)"); $dbh->commit(); }; # ... then check if there was an error. (Deadlock error is 1213.) if ($@) { if ($DBI::err == 1213) { print "Deadlock! Retrying ...\n"; redo; } else { print "Error! ($DBI::errstr) Exiting ...\n"; last; } } } $dbh->disconnect(); ------------------------------ This is slightly tedious to do every time I wish to perform a transaction. It would be nice if the database automatically retried a certain number of times itself before giving the error, and coming to think of it I've tried fiddling with a flag called "berkeley_trans_retry" in the MySQL source code (sql/ha_berkeley.cpp) which looked like it might do just that, but it didn't seem to make much difference. Maybe I'll put some debug in to see if it really is retrying 10 times when MySQL is built with the flag set to 10. Also, as the BerkeleyDB docs say, there is no guarantee that the transaction will ever succeed, which could be a bit of a problem (!) Is there any way to "favour" the transactions being performed by one client over those being performed by another to make sure some chosen client's transactions *do* always succeed? The docs simply say that one thread is selected to have its locks discarded (and receieve a deadlock error), but can I control *which* thread? In the real application code that I'm writing, I have two processes accessing the database (both of them both reading and writing), one of which is fairly busy all the time, the other of which only springs to life for a relatively short period of time about once an hour. I would like to "favour" the latter process during its short(ish) bursts of activity if possible. The other process could simply wait and retry, knowing that sooner or later the hourly process will finish it's burst of activity, enabling it to continue. >This happens rather seldom, as BDB uses page locks, which only block a >small part of the table. > What is a "page lock"? Is it a lock on one row, a certain number of rows, or the whole table? >>>A possible reason that you observe the rollback one time and not the >>>other could be that the mysql client sets auto-commit differently? >>> >>Both clients are instances of the same program running on the same >>machine, so I don't believe they are setting auto-commit differently. >> >Sorry, I meant the Perl vs. the command line client. I.e. Did you >assure, that the command line client also does not auto-commit, when >you run the INSERTs? > >I am not sure if you mean exactly this by your next comment, because >you interpreted my former statement differently. > >>Repeating the exercise explicitly setting "auto-commit=0;" in each of >>them makes do difference either. >> OK, I'm now definitely running the two command line clients in NON auto-commit mode, and it DOES make difference. I must have cocked it up before when I thought it made no difference. If I put the following Perl code into a file called "insert.pl" and then run "perl insert.pl | \mysql\bin\mysql -u root test" then I do get one or other client falling over quickly with the error "ERROR 1213 at line 3716: Deadlock found when trying to get lock; Try restarting transaction". ------------------------------ print "SET AUTOCOMMIT=0;\n"; for my $i (1 .. 10000) { print "INSERT INTO x (id) VALUES ($i);\n"; print "COMMIT;\n"; } ------------------------------ >Okay, now we know the fact that the processes may deadlock. The >question is why it does not happen in every environment. > >That it does not happen with Sybase could simply mean, that Sybase >uses a different locking approach or is able to lock inserts in a way >that would never deadlock. I don't know Sybase good enough to comment >on this. > Nor me. >Well, that DBD::ADO and the mysql client work could mean, that >auto-commit is enabled - could you check that it is in fact disabled >on the server side by quering the value... hm. I don't find a way to >query the status of a variable set via SET. Well, then how about >trying to create a deadlock by purpose (using an explicit LOCK TABLE >for the first client and an update for the second or so...). > As described above, I think the mysql client must have been autocommitting before. Now that autocommit is definitely disabled it gets deadlock too. So presumably DBD::ADO is also autocommitting. (Perhaps it doesn't honour the AutoCommit flag in my Perl program?) >Hm. Maybe I am completely wrong and MySQL/BDB works in a way that >INSERTs of two clients are distributed to pages so that they don't >conflict (i.e. starting a new page for the second client), but I >couldn't find any hint on that in one of the two manual. > If anybody else out there knows anything relevant about page locks in MySQL/BDB, I'd be glad to hear it. Thanks, Steve --------------------------------------------------------------------- Before posting, please check: http://www.mysql.com/manual.php (the manual) http://lists.mysql.com/ (the list archive) To request this thread, e-mail <[EMAIL PROTECTED]> To unsubscribe, e-mail <[EMAIL PROTECTED]> Trouble unsubscribing? Try: http://lists.mysql.com/php/unsubscribe.php