#!/usr/bin/perl

use threads;
use strict;
use warnings;

use DBI;
use Time::HiRes qw(sleep);


my ($dbname, $dbuser, $dbpass) = ("OOM", "<username>", "<password>");
my $threadsCount = 20;
my $secureWithNamedLock = 0;

my %threadInfos;

$SIG{TERM} = sub {
  warn "Terminating...\n";
  foreach my $thread (map { $_->{thread} } values %threadInfos) {
    $thread->kill('TERM')->join();
  }
  warn "All threads are killed. Exiting.\n";
};

# start the threads
foreach my $i (1..$threadsCount)
{
  my $thread = threads->create( sub {
    local $SIG{TERM} = sub {
      warn sprintf("thread received term signal\n");
      die "stopped\n";
    };
    eval {
      my $dbh = DBI->connect(
        sprintf("DBI:mysql:host=%s;database=%s", "localhost", $dbname),
        $dbuser,
        $dbpass,
        { RaiseError => 1, },
      ) or die sprintf("Cannot connect to database (%s).\n", $dbname);

      my @modes = qw(WRITE);
      my @tables = qw(table_to_update with_trigger2);
      my @tables2 = qw(with_trigger2 with_trigger3);
      foreach (1..10)
      {
        my $table = getRandomValue(@tables);
        my $mode = getRandomValue(@modes);
        my $lockSQL = "LOCK TABLES $table $mode";
        printf("Locking tables: %s\n", $lockSQL);
        $dbh->do("SELECT GET_LOCK('OOM_FIX', -1)")
          if $secureWithNamedLock;
        $dbh->do($lockSQL);
        sleep 0.1;
        printf("Unlocking tables\n");
        $dbh->do("UNLOCK TABLES");
        $dbh->do("SELECT RELEASE_LOCK('OOM_FIX')")
          if $secureWithNamedLock;
      }
    };
    my $error = $@;
    if ($error) {
      die $error unless $error ne "stopped\n";
    }
  });
  
  $threadInfos{$i} = {
    thread => $thread,
  };
}
  
my $runningThreads;
do {
  print "Checking threads...\n";
  $runningThreads = 0;
  foreach my $threadInfo (values %threadInfos) {
    my $thread = $threadInfo->{'thread'};
    next unless $thread;
    if ($thread->is_running()) {
      $runningThreads++;
    }
    elsif ($thread->is_joinable()) {
      printf("joining finished thread with id: %s\n", $thread->tid);
      $thread->join;
    }
  }
  
  sleep 1;
} while ($runningThreads > 0);

exit 0;

sub getRandomValue
{
  return $_[int(rand(scalar(@_)))];
}

