Advertisement
pmorch

Generate Transaction Deadlock Example

Oct 29th, 2014
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 2.60 KB | None | 0 0
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use Fcntl qw(:flock);
  4. use DBI;
  5. use Data::Dumper;
  6.  
  7. =head1 transaction deadlock
  8.  
  9. Run this a couple of times, and you'll eventually see:
  10.  
  11.     Running 2 children...
  12.     Error: 1213 / Deadlock found when trying to get lock; \
  13.             try restarting transaction
  14.     Finished child
  15.     Finished child
  16.     2 Children Finished...
  17.  
  18.     One should be prepared to issue transactions again if they fail - see
  19.         "How to Cope with Deadlocks"
  20.         http://dev.mysql.com/doc/refman/5.0/en/innodb-deadlocks.html
  21.     , but we won't do that here - we'll avoid using transactions instead.
  22.  
  23. =cut
  24.  
  25. my $flockFile = sprintf "/tmp/lockfile.flock";
  26. my $NUM_CHILDREN = 2;
  27.  
  28. sub getDBH {
  29.     return DBI->connect(
  30.         sprintf(
  31.             "DBI:mysql:database=%s;host=%s;port=%s",
  32.             'dbname',
  33.             'localhost',
  34.             'unixsocket'
  35.         ),
  36.         'user',
  37.         'pass',
  38.         { PrintError => 0, AutoCommit => 1 } );
  39. }
  40.  
  41. # Table is created further down - search for 'CREATE TABLE'
  42.  
  43. sub runTransaction {
  44.     my ($childNum) = @_;
  45.     my $dbh = getDBH;
  46.     my $insertSTH = $dbh->prepare('
  47.        INSERT INTO transactiontest
  48.               (value)
  49.        SELECT ?
  50.          FROM DUAL
  51.          WHERE NOT EXISTS (
  52.            SELECT value
  53.              FROM transactiontest
  54.             WHERE value=?
  55.          )
  56.    ');
  57.  
  58.     my $value = 1;
  59.  
  60.     $dbh->{AutoCommit} = 0;
  61.  
  62.     my $rowsAffected = $insertSTH->execute($value, $value);
  63.     if (! $rowsAffected) {
  64.         printf "Error: %s / %s\n",
  65.                 ($dbh->err // '<undef>'),
  66.                 ($dbh->errstr // '<undef>');
  67.     }
  68.     $dbh->commit;
  69. }
  70.  
  71. sub inChild {
  72.     open my $i, '<', $flockFile;
  73.     flock($i, LOCK_SH);
  74.  
  75.     runTransaction(@_);
  76.  
  77.     print "Finished child\n";
  78.     flock($i, LOCK_UN);
  79.     close $i;
  80.     exit;
  81. }
  82.  
  83. open my $flockExH, '>', $flockFile;
  84. flock($flockExH, LOCK_EX);
  85.  
  86. my @children;
  87. for (1..$NUM_CHILDREN) {
  88.     my $pid = fork();
  89.     if ($pid) {
  90.         # master
  91.         push @children, $pid;
  92.     } else {
  93.         close $flockExH;
  94.         inChild($_);
  95.     }
  96. }
  97.  
  98. my $dbh = getDBH;
  99. $dbh->prepare('
  100. DROP TABLE IF EXISTS `transactiontest`;
  101. ')->execute()
  102.     or die "Couldn't drop table";
  103.  
  104. $dbh->prepare('
  105. CREATE TABLE `transactiontest` (
  106.    `value` INT NOT NULL
  107. ) ENGINE = Innodb;
  108. ')->execute()
  109.     or die "Couldn't create table";
  110.  
  111. printf "Running %d children...\n", $NUM_CHILDREN;
  112. flock($flockExH, LOCK_UN);
  113. close $flockExH;
  114.  
  115. foreach my $pid (@children) {
  116.     waitpid $pid, 0;
  117. }
  118.  
  119. printf "%d Children Finished...\n", $NUM_CHILDREN;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement