mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-14 10:13:05 +02:00
Abortive attempt at cleaning up some thread issues - I realized the issue is in mixing threads and objects too liberally. Trying another approach but want to keep this code for historical and reference purposes.
This commit is contained in:
parent
fb934ecce9
commit
e95631f82a
@ -75,6 +75,7 @@ pg_backrest.pl [options] [operation]
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
####################################################################################################################################
|
||||
# Global variables
|
||||
####################################################################################################################################
|
||||
@ -124,11 +125,14 @@ sub remote_exit
|
||||
|
||||
if (defined($oRemote))
|
||||
{
|
||||
$oRemote->thread_kill()
|
||||
$oRemote = undef;
|
||||
}
|
||||
|
||||
BackRest::ThreadGroup::print();
|
||||
|
||||
if (defined($iExitCode))
|
||||
{
|
||||
&log(DEBUG, "process exited with code ${iExitCode}");
|
||||
exit $iExitCode;
|
||||
}
|
||||
}
|
||||
@ -261,6 +265,8 @@ if (operation_get() eq OP_ARCHIVE_PUSH)
|
||||
{
|
||||
&log(INFO, 'No fork on archive local for TESTING');
|
||||
}
|
||||
|
||||
$oFile = undef;
|
||||
}
|
||||
|
||||
# If no backup host is defined it makes no sense to run archive-push without a specified archive file so throw an error
|
||||
@ -329,6 +335,8 @@ if (operation_get() eq OP_ARCHIVE_PUSH)
|
||||
&log(DEBUG, 'no more logs to transfer - exiting');
|
||||
}
|
||||
}
|
||||
|
||||
$oFile = undef;
|
||||
#
|
||||
# };
|
||||
|
||||
@ -414,6 +422,8 @@ if (operation_get() eq OP_ARCHIVE_GET)
|
||||
|
||||
# Get the archive file
|
||||
remote_exit(archive_get(config_key_load(CONFIG_SECTION_STANZA, CONFIG_KEY_PATH), $ARGV[1], $ARGV[2]));
|
||||
|
||||
$oFile = undef;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@ -551,6 +561,7 @@ if (operation_get() eq OP_EXPIRE)
|
||||
lock_file_remove();
|
||||
}
|
||||
|
||||
$oFile->DESTROY();
|
||||
remote_exit(0);
|
||||
};
|
||||
|
||||
|
@ -1226,6 +1226,10 @@ sub backup_file
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Create threads to process the thread queues
|
||||
my $oThreadGroup = new BackRest::ThreadGroup('backup');
|
||||
|
||||
# End each thread queue and start the backup_file threads
|
||||
for (my $iThreadIdx = 0; $iThreadIdx < $iThreadLocalMax; $iThreadIdx++)
|
||||
{
|
||||
@ -1239,12 +1243,13 @@ sub backup_file
|
||||
$oThreadQueue[$iThreadIdx]->enqueue(undef);
|
||||
|
||||
# Start the thread
|
||||
$oThread[$iThreadIdx] = threads->create(\&backup_file_thread, $iThreadIdx, !$bNoChecksum, !$bPathCreate,
|
||||
$oyThreadData[$iThreadIdx]{size});
|
||||
$oThreadGroup->add(threads->create(\&backup_file_thread, $iThreadIdx, !$bNoChecksum, !$bPathCreate,
|
||||
$oyThreadData[$iThreadIdx]{size}));
|
||||
}
|
||||
|
||||
# Wait for the threads to complete
|
||||
backup_thread_complete($iThreadTimeout);
|
||||
# backup_thread_complete($iThreadTimeout);
|
||||
$oThreadGroup->complete(30);
|
||||
|
||||
# Read the messages that we passed back from the threads. These should be two types:
|
||||
# 1) remove - files that were skipped because they were removed from the database during backup
|
||||
@ -1375,6 +1380,7 @@ sub backup_file_thread
|
||||
}
|
||||
|
||||
&log(DEBUG, "thread ${iThreadIdx} exiting");
|
||||
# $oFileThread = undef;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@ -1675,13 +1681,18 @@ sub backup
|
||||
my $strFileLog = "pg_xlog/${strArchive}";
|
||||
|
||||
# Get the checksum and compare against the one already on log log file (if there is one)
|
||||
my $strChecksum = $oFile->hash(PATH_BACKUP_TMP, $strDestinationFile, $bCompress);
|
||||
my $strChecksum = undef;
|
||||
|
||||
if ($stryArchiveFile[0] =~ "^${strArchive}-[0-f]+(\\.$oFile->{strCompressExtension}){0,1}\$" &&
|
||||
$stryArchiveFile[0] !~ "^${strArchive}-${strChecksum}(\\.$oFile->{strCompressExtension}){0,1}\$")
|
||||
if (!$bNoChecksum)
|
||||
{
|
||||
confess &log(ERROR, "error copying log '$stryArchiveFile[0]' to backup - checksum recored with file does " .
|
||||
"not match actual checksum of '${strChecksum}'", ERROR_CHECKSUM);
|
||||
$strChecksum = $oFile->hash(PATH_BACKUP_TMP, $strDestinationFile, $bCompress);
|
||||
|
||||
if ($stryArchiveFile[0] =~ "^${strArchive}-[0-f]+(\\.$oFile->{strCompressExtension}){0,1}\$" &&
|
||||
$stryArchiveFile[0] !~ "^${strArchive}-${strChecksum}(\\.$oFile->{strCompressExtension}){0,1}\$")
|
||||
{
|
||||
confess &log(ERROR, "error copying log '$stryArchiveFile[0]' to backup - checksum recored with file does " .
|
||||
"not match actual checksum of '${strChecksum}'", ERROR_CHECKSUM);
|
||||
}
|
||||
}
|
||||
|
||||
# Set manifest values
|
||||
@ -1692,7 +1703,11 @@ sub backup
|
||||
$oBackupManifest->set($strFileSection, $strFileLog, MANIFEST_SUBKEY_MODE, '0700');
|
||||
$oBackupManifest->set($strFileSection, $strFileLog, MANIFEST_SUBKEY_MODIFICATION_TIME, $lModificationTime);
|
||||
$oBackupManifest->set($strFileSection, $strFileLog, MANIFEST_SUBKEY_SIZE, 16777216);
|
||||
$oBackupManifest->set($strFileSection, $strFileLog, MANIFEST_SUBKEY_CHECKSUM, $strChecksum);
|
||||
|
||||
if (defined($strChecksum))
|
||||
{
|
||||
$oBackupManifest->set($strFileSection, $strFileLog, MANIFEST_SUBKEY_CHECKSUM, $strChecksum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,10 +113,14 @@ sub new
|
||||
my $strDefaultFilePermission = shift;
|
||||
my $iThreadIdx = shift;
|
||||
|
||||
&log(TRACE, 'BackRest::File create' . (defined($iThreadIdx) ? " 'thread ${iThreadIdx}'" : ''));
|
||||
|
||||
# Create the class hash
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
$self->{iThreadId} = threads->tid();
|
||||
|
||||
# Default compression extension to gz
|
||||
$self->{strCompressExtension} = 'gz';
|
||||
|
||||
@ -154,19 +158,26 @@ sub new
|
||||
####################################################################################################################################
|
||||
# DESTRUCTOR
|
||||
####################################################################################################################################
|
||||
sub DEMOLISH
|
||||
sub DESTROY
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
if (defined($self->{oRemote}))
|
||||
{
|
||||
$self->{oRemote} = undef;
|
||||
}
|
||||
# if ($self->{iThreadId} != threads->tid())
|
||||
# {
|
||||
# return;
|
||||
# }
|
||||
|
||||
if (defined($self->{oProcessAsync}))
|
||||
{
|
||||
$self->{oProcessAsync} = undef;
|
||||
}
|
||||
&log(TRACE, 'BackRest::File destroy' . (defined($self->{iThreadIdx}) ? " 'thread $self->{iThreadIdx}'" : ''));
|
||||
|
||||
# if (defined($self->{oRemote}))
|
||||
# {
|
||||
# $self->{oRemote} = undef;
|
||||
# }
|
||||
#
|
||||
# if (defined($self->{oProcessAsync}))
|
||||
# {
|
||||
# $self->{oProcessAsync} = undef;
|
||||
# }
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
|
@ -16,6 +16,7 @@ use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Utility;
|
||||
use BackRest::ThreadGroup;
|
||||
|
||||
####################################################################################################################################
|
||||
# CONSTRUCTOR
|
||||
@ -28,10 +29,16 @@ sub new
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
&log(TRACE, ref($self) . " create [$self]");
|
||||
|
||||
$self->{iThreadId} = threads->tid();
|
||||
|
||||
# Initialize thread and queues
|
||||
$self->{oThreadQueue} = Thread::Queue->new();
|
||||
$self->{oThreadResult} = Thread::Queue->new();
|
||||
$self->{oThread} = threads->create(\&process_thread, $self);
|
||||
|
||||
$self->{oThreadGroup} = new BackRest::ThreadGroup('process_async');
|
||||
$self->{oThreadGroup}->add(threads->create(\&process_thread, $self));
|
||||
|
||||
return $self;
|
||||
}
|
||||
@ -39,17 +46,18 @@ sub new
|
||||
####################################################################################################################################
|
||||
# THREAD_KILL
|
||||
####################################################################################################################################
|
||||
sub thread_kill
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
if (defined($self->{oThread}))
|
||||
{
|
||||
$self->{oThreadQueue}->enqueue(undef);
|
||||
$self->{oThread}->join();
|
||||
$self->{oThread} = undef;
|
||||
}
|
||||
}
|
||||
# sub thread_kill
|
||||
# {
|
||||
# my $self = shift;
|
||||
#
|
||||
# if (defined($self->{oThreadGroup}))
|
||||
# {
|
||||
# $self->{oThreadQueue}->enqueue(undef);
|
||||
# $self->{oThreadGroup}->complete();
|
||||
# $self->{oThread}->join();
|
||||
# $self->{oThread} = undef;
|
||||
# }
|
||||
# }
|
||||
|
||||
####################################################################################################################################
|
||||
# DESTRUCTOR
|
||||
@ -58,7 +66,19 @@ sub DESTROY
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
$self->thread_kill();
|
||||
if ($self->{iThreadId} != threads->tid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
&log(TRACE, ref($self) . " destroy [$self]");
|
||||
|
||||
if (defined($self->{oThreadGroup}))
|
||||
{
|
||||
$self->{oThreadQueue}->enqueue(undef);
|
||||
$self->{oThreadGroup}->complete();
|
||||
# $self->{oThreadGroup} = undef;
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@ -70,6 +90,9 @@ sub process_thread
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# When a KILL signal is received, immediately abort
|
||||
$SIG{'KILL'} = sub {threads->exit();};
|
||||
|
||||
while (my $strMessage = $self->{oThreadQueue}->dequeue())
|
||||
{
|
||||
my @stryMessage = split(':', $strMessage);
|
||||
|
@ -55,6 +55,8 @@ sub new
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
&log(TRACE, ref($self) . " create");
|
||||
|
||||
# Create the greeting that will be used to check versions with the remote
|
||||
$self->{strGreeting} = 'PG_BACKREST_REMOTE ' . version_get();
|
||||
|
||||
@ -111,24 +113,31 @@ sub new
|
||||
####################################################################################################################################
|
||||
# THREAD_KILL
|
||||
####################################################################################################################################
|
||||
sub thread_kill
|
||||
# sub thread_kill
|
||||
# {
|
||||
# my $self = shift;
|
||||
#
|
||||
# if (defined($self->{oCompressAsync}))
|
||||
# {
|
||||
# $self->{oCompressAsync} = undef;
|
||||
# }
|
||||
# }
|
||||
|
||||
####################################################################################################################################
|
||||
# DESTRUCTOR
|
||||
####################################################################################################################################
|
||||
sub DESTROY
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
&log(TRACE, 'destroy BackRest::Remote');
|
||||
|
||||
if (defined($self->{oCompressAsync}))
|
||||
{
|
||||
$self->{oCompressAsync} = undef;
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# DESTRUCTOR
|
||||
####################################################################################################################################
|
||||
sub DEMOLISH
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
$self->thread_kill();
|
||||
# $self->thread_kill();
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
|
@ -584,7 +584,7 @@ sub restore
|
||||
}
|
||||
|
||||
# Create threads to process the thread queues
|
||||
my $oThreadGroup = new BackRest::ThreadGroup();
|
||||
my $oThreadGroup = new BackRest::ThreadGroup('restore');
|
||||
|
||||
for (my $iThreadIdx = 0; $iThreadIdx < $self->{iThreadTotal}; $iThreadIdx++)
|
||||
{
|
||||
|
@ -4,28 +4,61 @@
|
||||
package BackRest::ThreadGroup;
|
||||
|
||||
use threads;
|
||||
use threads::shared;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Carp;
|
||||
|
||||
use File::Basename;
|
||||
use Time::HiRes qw(gettimeofday usleep);
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Utility;
|
||||
|
||||
####################################################################################################################################
|
||||
# Shared for all objects
|
||||
####################################################################################################################################
|
||||
my %oThreadGroupHash :shared; # Stores active thread groups
|
||||
|
||||
####################################################################################################################################
|
||||
# CONSTRUCTOR
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift; # Class name
|
||||
my $strClass = shift; # Class name
|
||||
my $strDescription = shift; # Description of the group
|
||||
|
||||
# strDescription must be defined
|
||||
if (!defined($strDescription))
|
||||
{
|
||||
confess &log(ASSERT, 'strDescription is not defined');
|
||||
}
|
||||
|
||||
# Create the label based on time and description
|
||||
hsleep(.001);
|
||||
my $strLabel = '[' . gettimeofday() . '] ' . $strDescription;
|
||||
|
||||
# Create the class hash
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
bless $self, $strClass;
|
||||
|
||||
&log(TRACE, ref($self) . " create [$self] '${strLabel}'");
|
||||
|
||||
# Initialize variables
|
||||
$self->{iThreadTotal} = 0;
|
||||
$self->{iThreadId} = threads->tid();
|
||||
|
||||
# Lock the group has so that mods are synchronized
|
||||
lock(%oThreadGroupHash);
|
||||
|
||||
# Add the time to the description and store it as the label, making sure there are no collisions
|
||||
if (defined($oThreadGroupHash{$strLabel}))
|
||||
{
|
||||
confess &log(ASSERT, "collision detected in thread group '${strLabel}'");
|
||||
}
|
||||
|
||||
$self->{strLabel} = shared_clone($strLabel);
|
||||
$oThreadGroupHash{$self->{strLabel}} = true;
|
||||
|
||||
return $self;
|
||||
}
|
||||
@ -40,6 +73,8 @@ sub add
|
||||
my $self = shift;
|
||||
my $oThread = shift;
|
||||
|
||||
&log(TRACE, ref($self) . " add [$self], thread [$oThread]");
|
||||
|
||||
$self->{oyThread}[$self->{iThreadTotal}] = $oThread;
|
||||
$self->{iThreadTotal}++;
|
||||
|
||||
@ -67,7 +102,9 @@ sub complete
|
||||
# Rejoin the threads
|
||||
while ($iThreadComplete < $self->{iThreadTotal})
|
||||
{
|
||||
hsleep(.1);
|
||||
# hsleep(.1);
|
||||
hsleep(1);
|
||||
&log(TRACE, 'waiting for threads to exit');
|
||||
|
||||
# If a timeout has been defined, make sure we have not been running longer than that
|
||||
if (defined($iTimeout))
|
||||
@ -88,7 +125,7 @@ sub complete
|
||||
{
|
||||
if (defined($self->{oyThread}[$iThreadIdx]->error()))
|
||||
{
|
||||
$self->kill();
|
||||
# $self->kill();
|
||||
|
||||
if ($bConfessOnError)
|
||||
{
|
||||
@ -140,7 +177,7 @@ sub kill
|
||||
$self->{oyThread}[$iThreadIdx]->join();
|
||||
}
|
||||
|
||||
undef($self->{oyThread}[$iThreadIdx]);
|
||||
$self->{oyThread}[$iThreadIdx] = undef;
|
||||
$iTotal++;
|
||||
}
|
||||
}
|
||||
@ -151,11 +188,43 @@ sub kill
|
||||
####################################################################################################################################
|
||||
# DESTRUCTOR
|
||||
####################################################################################################################################
|
||||
sub DEMOLISH
|
||||
sub DESTROY
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
if ($self->{iThreadId} != threads->tid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
&log(TRACE, "BackRest::ThreadGroup destroy [$self] '$self->{strLabel}'");
|
||||
|
||||
$self->kill();
|
||||
|
||||
# Lock the group hash and delete the current group
|
||||
lock(%oThreadGroupHash);
|
||||
|
||||
if (!defined($oThreadGroupHash{$self->{strLabel}}))
|
||||
{
|
||||
confess &log(ASSERT, "BackRest::ThreadGroup [$self] '$self->{strLabel}' has already been destroyed");
|
||||
}
|
||||
|
||||
delete($oThreadGroupHash{$self->{strLabel}});
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# print
|
||||
####################################################################################################################################
|
||||
sub print
|
||||
{
|
||||
# Lock the group hash
|
||||
lock(%oThreadGroupHash);
|
||||
|
||||
# print all active groups
|
||||
foreach my $strLabel (sort(keys %oThreadGroupHash))
|
||||
{
|
||||
&log(TRACE, "BackRest::ThreadGroup active '${strLabel}'");
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -180,6 +180,8 @@ sub BackRestTestCommon_ExecuteEnd
|
||||
# Check the exit status and output an error if needed
|
||||
my $iExitStatus = ${^CHILD_ERROR_NATIVE} >> 8;
|
||||
|
||||
&log(TRACE, "command exited with status ${iExitStatus}");
|
||||
|
||||
if (defined($iExpectedExitStatus) && $iExitStatus == $iExpectedExitStatus)
|
||||
{
|
||||
return $iExitStatus;
|
||||
@ -519,7 +521,7 @@ sub BackRestTestCommon_ConfigCreate
|
||||
}
|
||||
|
||||
$oParamHash{'global:log'}{'level-console'} = 'error';
|
||||
$oParamHash{'global:log'}{'level-file'} = 'debug';
|
||||
$oParamHash{'global:log'}{'level-file'} = 'trace';
|
||||
|
||||
if ($strLocal eq BACKUP)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user