@@ -2954,6 +2954,154 @@ sub lsn
29542954
29552955=pod
29562956
2957+ =item $node->write_wal($tli, $lsn, $segment_size, $data)
2958+
2959+ Write some arbitrary data in WAL for the given segment at $lsn (in bytes).
2960+ This should be called while the cluster is not running.
2961+
2962+ Returns the path of the WAL segment written to.
2963+
2964+ =cut
2965+
2966+ sub write_wal
2967+ {
2968+ my ($self , $tli , $lsn , $segment_size , $data ) = @_ ;
2969+
2970+ # Calculate segment number and offset position in segment based on the
2971+ # input LSN.
2972+ my $segment = $lsn / $segment_size ;
2973+ my $offset = $lsn % $segment_size ;
2974+ my $path =
2975+ sprintf (" %s /pg_wal/%08X%08X%08X" , $self -> data_dir, $tli , 0, $segment );
2976+
2977+ open my $fh , " +<:raw" , $path or die " could not open WAL segment $path " ;
2978+ seek ($fh , $offset , SEEK_SET) or die " could not seek WAL segment $path " ;
2979+ print $fh $data ;
2980+ close $fh ;
2981+
2982+ return $path ;
2983+ }
2984+
2985+ =pod
2986+
2987+ =item $node->emit_wal($size)
2988+
2989+ Emit a WAL record of arbitrary size, using pg_logical_emit_message().
2990+
2991+ Returns the end LSN of the record inserted, in bytes.
2992+
2993+ =cut
2994+
2995+ sub emit_wal
2996+ {
2997+ my ($self , $size ) = @_ ;
2998+
2999+ return int (
3000+ $self -> safe_psql(
3001+ ' postgres' ,
3002+ " SELECT pg_logical_emit_message(true, '', repeat('a', $size )) - '0/0'"
3003+ ));
3004+ }
3005+
3006+
3007+ # Private routine returning the current insert LSN of a node, in bytes.
3008+ # Used by the routines below in charge of advancing WAL to arbitrary
3009+ # positions. The insert LSN is returned in bytes.
3010+ sub _get_insert_lsn
3011+ {
3012+ my ($self ) = @_ ;
3013+ return int (
3014+ $self -> safe_psql(
3015+ ' postgres' , " SELECT pg_current_wal_insert_lsn() - '0/0'" ));
3016+ }
3017+
3018+ =pod
3019+
3020+ =item $node->advance_wal_out_of_record_splitting_zone($wal_block_size)
3021+
3022+ Advance WAL at the end of a page, making sure that we are far away enough
3023+ from the end of a page that we could insert a couple of small records.
3024+
3025+ This inserts a few records of a fixed size, until the threshold gets close
3026+ enough to the end of the WAL page inserting records to.
3027+
3028+ Returns the end LSN up to which WAL has advanced, in bytes.
3029+
3030+ =cut
3031+
3032+ sub advance_wal_out_of_record_splitting_zone
3033+ {
3034+ my ($self , $wal_block_size ) = @_ ;
3035+
3036+ my $page_threshold = $wal_block_size / 4;
3037+ my $end_lsn = $self -> _get_insert_lsn();
3038+ my $page_offset = $end_lsn % $wal_block_size ;
3039+ while ($page_offset >= $wal_block_size - $page_threshold )
3040+ {
3041+ $self -> emit_wal($page_threshold );
3042+ $end_lsn = $self -> _get_insert_lsn();
3043+ $page_offset = $end_lsn % $wal_block_size ;
3044+ }
3045+ return $end_lsn ;
3046+ }
3047+
3048+ =pod
3049+
3050+ =item $node->advance_wal_to_record_splitting_zone($wal_block_size)
3051+
3052+ Advance WAL so close to the end of a page that an XLogRecordHeader would not
3053+ fit on it.
3054+
3055+ Returns the end LSN up to which WAL has advanced, in bytes.
3056+
3057+ =cut
3058+
3059+ sub advance_wal_to_record_splitting_zone
3060+ {
3061+ my ($self , $wal_block_size ) = @_ ;
3062+
3063+ # Size of record header.
3064+ my $RECORD_HEADER_SIZE = 24;
3065+
3066+ my $end_lsn = $self -> _get_insert_lsn();
3067+ my $page_offset = $end_lsn % $wal_block_size ;
3068+
3069+ # Get fairly close to the end of a page in big steps
3070+ while ($page_offset <= $wal_block_size - 512)
3071+ {
3072+ $self -> emit_wal($wal_block_size - $page_offset - 256);
3073+ $end_lsn = $self -> _get_insert_lsn();
3074+ $page_offset = $end_lsn % $wal_block_size ;
3075+ }
3076+
3077+ # Calibrate our message size so that we can get closer 8 bytes at
3078+ # a time.
3079+ my $message_size = $wal_block_size - 80;
3080+ while ($page_offset <= $wal_block_size - $RECORD_HEADER_SIZE )
3081+ {
3082+ $self -> emit_wal($message_size );
3083+ $end_lsn = $self -> _get_insert_lsn();
3084+
3085+ my $old_offset = $page_offset ;
3086+ $page_offset = $end_lsn % $wal_block_size ;
3087+
3088+ # Adjust the message size until it causes 8 bytes changes in
3089+ # offset, enough to be able to split a record header.
3090+ my $delta = $page_offset - $old_offset ;
3091+ if ($delta > 8)
3092+ {
3093+ $message_size -= 8;
3094+ }
3095+ elsif ($delta <= 0)
3096+ {
3097+ $message_size += 8;
3098+ }
3099+ }
3100+ return $end_lsn ;
3101+ }
3102+
3103+ =pod
3104+
29573105=item $node->check_extension(extension_name)
29583106
29593107Scan pg_available_extensions to check that an extension is available in an
0 commit comments