use strict;
use warnings;

use PostgresNode;
use TestLib;
use Test::More tests => 10;
use Config;

# Initialize primary node
my $node_primary = get_new_node('primary');
$node_primary->init(allows_streaming => 1);
$node_primary->append_conf('postgresql.conf', 'autovacuum=off');
$node_primary->append_conf('postgresql.conf', 'enable_seqscan=off');
my $pgdata = $node_primary->data_dir;
command_ok([ 'pg_checksums', '--enable', '--no-sync', '-D', $pgdata ],
	"checksums successfully enabled in cluster");
$node_primary->start;

# ADD EXTRA_INSTALL+=contrib/pageinspect to Makefile
$node_primary->safe_psql('postgres', 'CREATE EXTENSION pageinspect');

$node_primary->safe_psql('postgres', 'CREATE TABLE test_table (id int, value int, filler text)');
$node_primary->safe_psql('postgres', "INSERT INTO test_table VALUES (generate_series(1, 10), 0, '')");
$node_primary->safe_psql('postgres', 'CREATE INDEX test_index ON test_table (value, id)');

$node_primary->safe_psql('postgres', 'VACUUM test_table');
$node_primary->safe_psql('postgres', 'CHECKPOINT');

my $backup_name = 'my_backup';
$node_primary->backup($backup_name);

my $node_standby = get_new_node('standby');
$node_standby->init_from_backup($node_primary, $backup_name, has_streaming => 1);
$node_standby->append_conf('postgresql.conf', 'hot_standby_feedback=off');
$node_standby->start;

$node_primary->wait_for_catchup($node_standby, 'replay', $node_primary->lsn('insert'));

restart();

my $heap_primary_checksum = $node_primary->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_table', 0))");
my $heap_secondary_checksum = $node_standby->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_table', 0))");

my $index_primary_checksum = $node_primary->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_index', 1))");
my $index_secondary_checksum = $node_standby->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_index', 1))");

diag("\n" . $heap_primary_checksum . "\n");
diag("\n" . $heap_secondary_checksum . "\n");

is($heap_primary_checksum - $heap_secondary_checksum, qq(0), 'heap checksums are equal');
is($index_primary_checksum - $index_secondary_checksum, qq(0), 'index checksums are equal');

# delete record once
$node_primary->safe_psql('postgres', 'DELETE FROM test_table WHERE id = 1');
$node_primary->wait_for_catchup($node_standby, 'replay', $node_primary->lsn('insert'));

# move minRecoveryForward to allow hint bits to be set in the heap
$node_standby->safe_psql('postgres', 'CHECKPOINT');
# set hint bits in the heap on secondary
$node_standby->safe_psql('postgres', 'SELECT * FROM test_table');

restart();

$heap_primary_checksum = $node_primary->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_table', 0))");
$heap_secondary_checksum = $node_standby->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_table', 0))");

$index_primary_checksum = $node_primary->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_index', 1))");
$index_secondary_checksum = $node_standby->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_index', 1))");

# now heap pages on standby and primary has different checksums (because of hint bit on standby)
isnt($heap_primary_checksum - $heap_secondary_checksum, qq(0), 'heap checksums are different');
# but indexes are ok at the moment
is($index_primary_checksum - $index_secondary_checksum, qq(0), 'index checksums are still equal');

# set same hint bit on the heap on primary
$node_primary->safe_psql('postgres', 'SELECT * FROM test_table');
$node_primary->wait_for_catchup($node_standby, 'replay', $node_primary->lsn('insert'));

restart();

$heap_primary_checksum = $node_primary->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_table', 0))");
$heap_secondary_checksum = $node_standby->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_table', 0))");

# now everything is matched again
is($heap_primary_checksum - $heap_secondary_checksum, qq(0), 'heap checksums are equal again');
is($index_primary_checksum - $index_secondary_checksum, qq(0), 'index checksums are still equal');

restart();

# produce FPI of index page and mark it as dirty
$node_primary->safe_psql('postgres', "INSERT INTO test_table VALUES(11, 0, '')");
# scan index to set LP_DEAD
$node_primary->safe_psql('postgres', 'SELECT * FROM test_table order by value, id');

$node_primary->wait_for_catchup($node_standby, 'replay', $node_primary->lsn('insert'));

restart();

# now primary has LP_DEAD set
is(hints_num($node_primary), qq(1), 'LP_DEAD set on primary');
# but standby - no
is(hints_num($node_standby), qq(0), 'LP_DEAD is not set on standby');

$index_primary_checksum = $node_primary->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_index', 1))");
$index_secondary_checksum = $node_standby->safe_psql('postgres', "select checksum from page_header(get_raw_page('test_index', 1))");

# and index checksums are different now
isnt($index_primary_checksum - $index_secondary_checksum, qq(0), 'index checksums are now differs');

$node_primary->stop;
$node_standby->stop;

sub restart {
	$node_primary->stop;
	$node_standby->stop;
	$node_primary->start;
	$node_standby->start;
}

sub hints_num {
    my ($node) = @_;
    return $node->safe_psql('postgres', "SELECT count(*) FROM bt_page_items('test_index', 1) WHERE dead = true");
}
