summaryrefslogtreecommitdiff
path: root/mysql-test/suite/mariabackup/include/corrupt-page.pl
blob: d5c75dbde55c192f71c4d5828651ec43927ee4eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use strict;
use warnings;
use Fcntl qw(:DEFAULT :seek);
do "$ENV{MTR_SUITE_DIR}/../innodb/include/crc32.pl";

sub corrupt_space_page_id {
  my $file_name = shift;
  my @pages_to_corrupt = @_;

  my $page_size = $ENV{INNODB_PAGE_SIZE};

  sysopen my $ibd_file, $file_name, O_RDWR || die "Cannot open $file_name\n";
  sysread($ibd_file, $_, 38) || die "Cannot read $file_name\n";
  my $space = unpack("x[34]N", $_);
  foreach my $page_no (@pages_to_corrupt) {
    $space += 10; # generate wrong space id
    sysseek($ibd_file, $page_size * $page_no, SEEK_SET)
      || die "Cannot seek $file_name\n";

    my $head = pack("Nx[18]", $page_no + 10); # generate wrong page number
    my $body = chr(0) x ($page_size - 38 - 8);

    # Calculate innodb_checksum_algorithm=crc32 for the unencrypted page.
    # The following bytes are excluded:
    # bytes 0..3 (the checksum is stored there)
    # bytes 26..37 (encryption key version, post-encryption checksum, tablespace id)
    # bytes $page_size-8..$page_size-1 (checksum, LSB of FIL_PAGE_LSN)
    my $polynomial = 0x82f63b78; # CRC-32C
    my $ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial);

    my $page= pack("N",$ck).$head.pack("NNN",1,$ck,$space).$body.pack("Nx[4]",$ck);
    die unless syswrite($ibd_file, $page, $page_size) == $page_size;
  }
  close $ibd_file;
}

sub extend_space {
  my $file_name = shift;
  my $n_pages = shift;

  my $page_size = $ENV{INNODB_PAGE_SIZE};
  my $page;

  sysopen my $ibd_file, $file_name, O_RDWR || die "Cannot open $file_name\n";
  sysread($ibd_file, $page, $page_size)
    || die "Cannot read $file_name\n";
  my $size = unpack("N", substr($page, 46, 4));
  my $packed_new_size = pack("N", $size + $n_pages);
  substr($page, 46, 4, $packed_new_size);

  my $head = substr($page, 4, 22);
  my $body = substr($page, 38, $page_size - 38 - 8);
  my $polynomial = 0x82f63b78; # CRC-32C
  my $ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial);
  my $packed_ck = pack("N", $ck);
  substr($page, 0, 4, $packed_ck);
  substr($page, $page_size - 8, 4, $packed_ck);

  sysseek($ibd_file, 0, SEEK_SET)
      || die "Cannot seek $file_name\n";
  die unless syswrite($ibd_file, $page, $page_size) == $page_size;

  sysseek($ibd_file, 0, SEEK_END)
      || die "Cannot seek $file_name\n";
  my $pages_size = $page_size*$n_pages;
  my $pages = chr(0) x $pages_size;
  die unless syswrite($ibd_file, $pages, $pages_size) == $pages_size;
  close $ibd_file;
  return $size;
}

sub die_if_page_is_not_zero {
  my $file_name = shift;
  my @pages_to_check = @_;

  no locale;
  my $page_size = $ENV{INNODB_PAGE_SIZE};
  my $zero_page = chr(0) x $page_size;
  sysopen my $ibd_file, $file_name, O_RDWR || die "Cannot open $file_name\n";
  foreach my $page_no_to_check (@pages_to_check) {
    sysseek($ibd_file, $page_size*$page_no_to_check, SEEK_SET) ||
      die "Cannot seek $file_name\n";
    sysread($ibd_file, my $read_page, $page_size) ||
      die "Cannot read $file_name\n";
    die "The page $page_no_to_check is not zero-filed in $file_name"
      if ($read_page cmp $zero_page);
  }
  close $ibd_file;
}

sub print_corrupted_pages_file {
  my $file_in = shift;
  my $file_out = shift;
  open my $fh, '<', $file_in || die $!;
  my $line_number = 0;
  my $space = {};
  my @spaces;
  while (my $line = <$fh>) {
    ++$line_number;
    if ($line_number & 1) {
      my ($name, $id) = split(/ /, $line);
      $space->{name} = $name;
    }
    else {
      $space->{pages} = $line;
      push (@spaces, $space);
      $space = {};
    }
  }
  close $fh;
  my @sorted_spaces = sort { $a->{name} cmp $b->{name} } @spaces;
  open $fh, '>', $file_out || die $!;
  foreach my $space (@sorted_spaces) {
    print $fh $space->{name};
    print $fh "\n";
    print $fh $space->{pages};
  }
  close $fh;
}

sub append_corrupted_pages {
  my $file_name = shift;
  my $space_name = shift;
  my $pages = shift;
  open my $fh, '<', $file_name || die $!;
  my $line_number = 0;
  my $space_line;
  while (my $line = <$fh>) {
    ++$line_number;
    if ($line_number & 1) {
      my ($name, $id) = split(/ /, $line);
      if ($name eq $space_name) {
        $space_line = $line;
        last;
      }
    }
  }
  close $fh;
  if (not defined $space_line) {
    die "Can't find requested space $space_name in file $file_name";
  }
  open $fh, '>>', $file_name || die $!;
  print $fh $space_line;
  print $fh "$pages\n";
  close $fh;
}