partrotate_unixtimestamp.pl 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #!/usr/bin/perl
  2. #
  3. # partrotate_unixtimestamp - perl script for mySQL partition rotation
  4. #
  5. # Copyright (C) 2011-2014 Alexandr Dubovikov ([email protected])
  6. #
  7. # This file is part of webhomer, a free capture server.
  8. #
  9. # partrotate_unixtimestamp is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License as published by
  11. # the Free Software Foundation; either version 3 of the License, or
  12. # (at your option) any later version
  13. #
  14. # partrotate_unixtimestamp is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License
  20. # along with this program; if not, write to the Free Software
  21. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22. use DBI;
  23. $version = "0.3.1k";
  24. $mysql_table = "sip_capture";
  25. $mysql_dbname = "homer_db";
  26. $mysql_user = "mysql_login";
  27. $mysql_password = "mysql_password";
  28. $mysql_host = "localhost";
  29. $maxparts = 6; #6 days How long keep the data in the DB
  30. $newparts = 2; #new partitions for 2 days. Anyway, start this script daily!
  31. @stepsvalues = (86400, 3600, 1800, 900);
  32. $partstep = 0; # 0 - Day, 1 - Hour, 2 - 30 Minutes, 3 - 15 Minutes
  33. $engine = "InnoDB"; #MyISAM or InnoDB
  34. $compress = "ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8"; #Enable this if you want use barracuda format or set var to empty.
  35. $sql_schema_version = 2;
  36. $auth_column = "auth";
  37. $check_table = 1; #Check if table exists. For PostgreSQL change creation schema!
  38. #Check it
  39. $partstep=0 if(!defined $stepsvalues[$partstep]);
  40. #Mystep
  41. $mystep = $stepsvalues[$partstep];
  42. #Coof
  43. # Optionally load override configuration. perl format
  44. $rc = "/etc/sysconfig/partrotaterc";
  45. if (-e $rc) {
  46. do $rc;
  47. }
  48. $coof=int(86400/$mystep);
  49. #How much partitions
  50. $maxparts*=$coof;
  51. $newparts*=$coof;
  52. $totalparts = ($maxparts+$newparts);
  53. my $db = DBI->connect("DBI:mysql:$mysql_dbname:$mysql_host:3306", $mysql_user, $mysql_password);
  54. $auth_column = "authorization" if($sql_schema_version == 1);
  55. #$db->{PrintError} = 0;
  56. #check if the table has partitions. If not, create one
  57. my $query = "SHOW TABLE STATUS FROM ".$mysql_dbname. " WHERE Name='".$mysql_table."'";
  58. $sth = $db->prepare($query);
  59. $sth->execute();
  60. my $tstatus = $sth->fetchrow_hashref()->{Create_options};
  61. if ($tstatus !~ /partitioned/) {
  62. my $query = "ALTER TABLE ".$mysql_table. " PARTITION BY RANGE ( UNIX_TIMESTAMP(`date`)) (PARTITION pmax VALUES LESS THAN MAXVALUE)";
  63. $sth = $db->prepare($query);
  64. $sth->execute();
  65. }
  66. my $query = "SELECT UNIX_TIMESTAMP(CURDATE() - INTERVAL 1 DAY)";
  67. $sth = $db->prepare($query);
  68. $sth->execute();
  69. my ($curtstamp) = $sth->fetchrow_array();
  70. $curtstamp+=0;
  71. $todaytstamp+=0;
  72. my %PARTS;
  73. #Geting all partitions
  74. $query = "SELECT PARTITION_NAME, PARTITION_DESCRIPTION"
  75. ."\n FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='".$mysql_table."'"
  76. ."\n AND TABLE_SCHEMA='".$mysql_dbname."' ORDER BY PARTITION_DESCRIPTION ASC;";
  77. $sth = $db->prepare($query);
  78. $sth->execute();
  79. my @oldparts;
  80. my @partsremove;
  81. while(my @ref = $sth->fetchrow_array())
  82. {
  83. my $minpart = $ref[0];
  84. my $todaytstamp = $ref[1];
  85. next if($minpart eq "pmax");
  86. if($curtstamp <= $todaytstamp) {
  87. $PARTS{$minpart."_".$todaytstamp} = 1;
  88. }
  89. else { push(@oldparts, \@ref); }
  90. }
  91. my $partcount = $#oldparts;
  92. if($partcount > $maxparts)
  93. {
  94. foreach my $ref (@oldparts) {
  95. $minpart = $ref->[0];
  96. $todaytstamp = $ref->[1];
  97. push(@partsremove,$minpart);
  98. $partcount--;
  99. last if($partcount <= $maxparts);
  100. }
  101. }
  102. if($#partsremove > 0)
  103. {
  104. $query = "ALTER TABLE ".$mysql_table." DROP PARTITION ".join(',', @partsremove);
  105. $db->do($query);
  106. if (!$db->{Executed}) {
  107. print "Couldn't drop partition: $minpart\n";
  108. break;
  109. }
  110. }
  111. # < condition
  112. $curtstamp+=(86400);
  113. #Create new partitions
  114. for(my $i=0; $i<$newparts; $i++) {
  115. $oldstamp = $curtstamp;
  116. $curtstamp+=$mystep;
  117. ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($oldstamp);
  118. my $newpartname = sprintf("p%04d%02d%02d%02d",($year+=1900),(++$mon),$mday,$hour);
  119. $newpartname.= sprintf("%02d", $min) if($partstep > 1);
  120. if(!defined $PARTS{$newpartname."_".$curtstamp}) {
  121. # Fix MAXVALUE. Thanks Dorn B. <[email protected]> for report and fix.
  122. $query = "ALTER TABLE ".$mysql_table." REORGANIZE PARTITION pmax INTO (PARTITION ".$newpartname
  123. ."\n VALUES LESS THAN (".$curtstamp.") ENGINE = ".$engine.", PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = ".$engine.")";
  124. $db->do($query);
  125. if (!$db->{Executed}) {
  126. print "Couldn't add partition: $newpartname\n";
  127. }
  128. }
  129. }