You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by ar...@apache.org on 2017/03/16 15:37:33 UTC
svn commit: r1787209 - in /vcl/trunk/managementnode/lib/VCL:
DataStructure.pm Module.pm Module/OS/Linux.pm
Module/OS/Linux/ManagementNode.pm Module/Provisioning/VMware/VMware.pm
Module/Semaphore.pm new.pm
Author: arkurth
Date: Thu Mar 16 15:37:32 2017
New Revision: 1787209
URL: http://svn.apache.org/viewvc?rev=1787209&view=rev
Log:
VCL-1023
Reworked Semaphore.pm to use the new vcldsemaphore table instead of a lockfile on the management node. This allows semaphores to be obeyed for vcld processes running on different management nodes.
Added VMware.pm::get_datastore_directory_semaphore which retrieves a datastore's URL/UUID identifier and uses this to obtain a semaphore instead of the descriptive datastore name. This allows semaphores to be obeyed for a particular directory on a datastore, even if different hosts to mount the same datastore with using different names.
Updated VMware.pm::prepare_vmdk to use get_datastore_directory_semaphore.
Deleted no longer used subroutines:
* Module.pm::does_semaphore_exist
* Semaphore.pm::get_process_semaphore_ids
* Semaphore.pm::get_reservation_semaphore_ids
* Semaphore.pm::semaphore_exists
* Semaphore.pm::get_lockfile_paths
* Semaphore.pm::release_lockfile
Updated Module.pm to not call 'use VCL::Module::Semaphore' at the beginning. This causes subroutine redefined warnings because there's sort of a circular reference the way Module.pm uses Semaphore.pm and Semaphore.pm inherits from Module.pm. Added require and import statement inside of Module.pm::get_semaphore contained within an eval block as a replacement.
Updated new.pm::computer_not_being_used to use utils.pm::get_vcld_semaphore_info instead of calling Semaphore.pm::get_process_semaphore_ids.
Other
Added DataStructure.pm::get_connect_method_info_matching_name. It was used for some experimentation and isn't currently being called, but may be useful in the future.
Updated Linux.pm::get_network_bridge_info to check for exit statuses > 0 instead of anything != 0. Perl occasionally returns -1 even though the command was successful.
Modified:
vcl/trunk/managementnode/lib/VCL/DataStructure.pm
vcl/trunk/managementnode/lib/VCL/Module.pm
vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/ManagementNode.pm
vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm
vcl/trunk/managementnode/lib/VCL/Module/Semaphore.pm
vcl/trunk/managementnode/lib/VCL/new.pm
Modified: vcl/trunk/managementnode/lib/VCL/DataStructure.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/DataStructure.pm?rev=1787209&r1=1787208&r2=1787209&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/DataStructure.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/DataStructure.pm Thu Mar 16 15:37:32 2017
@@ -2332,6 +2332,60 @@ sub get_reservation_info_json_string {
return $json;
}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_connect_method_info_matching_name
+
+ Parameters : $regex_pattern
+ Returns : hash reference
+ Description : Checks the name of all connect methods mapped to the current
+ reservation's image revision. Returns info for all connect
+ methods with a connectmethod.name value matching the pattern
+ argument. This is useful for finding a particular connect method.
+
+ For example:
+ $self->data->get_connect_method_info_matching_name('vmware');
+
+ A hash reference is returned. The only hash element would be
+ information about a "VMwareVNC" connect method.
+
+=cut
+
+sub get_connect_method_info_matching_name {
+ my $self = shift;
+ if (ref($self) !~ /VCL::/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return;
+ }
+
+ my $regex_pattern = shift;
+ if (!defined($regex_pattern)) {
+ notify($ERRORS{'WARNING'}, 0, "connect method name regex pattern argument was not supplied");
+ return;
+ }
+
+ my $matching_connect_method_info = {};
+
+ my $connect_method_info = $self->get_connect_methods();
+ for my $connect_method_id (sort {$a <=> $b} keys %$connect_method_info) {
+ my $connect_method = $connect_method_info->{$connect_method_id};
+ my $connect_method_name = $connect_method->{name};
+ if ($connect_method_name =~ /$regex_pattern/i) {
+ $matching_connect_method_info->{$connect_method_id} = $connect_method;
+ }
+ }
+
+ my $matching_count = scalar(keys %$matching_connect_method_info);
+ if (!$matching_count) {
+ notify($ERRORS{'DEBUG'}, 0, "no connect methods with name matching pattern '$regex_pattern' are mapped to image revision assigned to reservation");
+ }
+ else {
+ notify($ERRORS{'DEBUG'}, 0, "found $matching_count connect method(s) with name matching pattern '$regex_pattern' mapped to image revision assigned to reservation:\n" . format_data($matching_connect_method_info));
+ }
+ return $matching_connect_method_info;
+}
+
#/////////////////////////////////////////////////////////////////////////////
1;
Modified: vcl/trunk/managementnode/lib/VCL/Module.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module.pm?rev=1787209&r1=1787208&r2=1787209&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module.pm Thu Mar 16 15:37:32 2017
@@ -90,7 +90,6 @@ use Digest::SHA1 qw(sha1_hex);
use VCL::utils;
use VCL::DataStructure;
-use VCL::Module::Semaphore;
##############################################################################
@@ -1533,7 +1532,7 @@ sub code_loop_timeout {
=head2 get_semaphore
- Parameters : $semaphore_id, $total_wait_seconds (optional), $attempt_delay_seconds (optional)
+ Parameters : $semaphore_identifier, $semaphore_expire_seconds (optional), $attempt_delay_seconds (optional)
Returns : VCL::Module::Semaphore object
Description : This subroutine is used to ensure that only 1 process performs a
particular task at a time. An example would be the retrieval of
@@ -1544,32 +1543,24 @@ sub code_loop_timeout {
others will wait until the semaphore is released by the
retrieving process.
- Attempts to open and obtain an exclusive lock on the file
- specified by the file path argument. If unable to obtain an
- exclusive lock, it will wait up to the value specified by the
- total wait seconds argument (default: 30 seconds). The number of
- seconds to wait in between retries can be specified (default: 15
- seconds).
-
- A semaphore object is returned. The exclusive lock will be
- retained as long as the semaphore object remains defined. Once
- undefined, the exclusive lock is released and the file is
- deleted.
+ A semaphore object is returned. The semaphore will be retained as
+ long as the semaphore object remains defined. Once undefined, the
+ semaphore is released.
Examples:
Semaphore is released when it is undefined:
my $semaphore = $self->get_semaphore('test');
- ... <exclusive lock is in place>
+ ... <semaphore in place>
undef $semaphore;
- ... <exclusive lock released>
+ ... <semaphore released>
Semaphore is released when it goes out of scope:
if (blah) {
my $semaphore = $self->get_semaphore('test');
- ... <exclusive lock is in place>
+ ... <semaphore in place>
}
- ... <exclusive lock released>
+ ... <semaphore released>
=cut
@@ -1581,67 +1572,38 @@ sub get_semaphore {
}
# Get the file path argument
- my ($semaphore_id, $total_wait_seconds, $attempt_delay_seconds) = @_;
- if (!$semaphore_id) {
- notify($ERRORS{'WARNING'}, 0, "semaphore ID argument was not supplied");
+ my ($semaphore_identifier, $semaphore_expire_seconds, $attempt_delay_seconds) = @_;
+ if (!$semaphore_identifier) {
+ notify($ERRORS{'WARNING'}, 0, "semaphore identifier argument was not supplied");
return;
}
# Attempt to create a new semaphore object
+ # Load Semaphore.pm here instead of calling use
+ # This prevents "Subroutine ... redefined" warnings
+ eval {
+ require "VCL/Module/Semaphore.pm";
+ import VCL::Module::Semaphore;
+ };
my $semaphore = VCL::Module::Semaphore->new({'data_structure' => $self->data, mn_os => $self->mn_os});
if (!$semaphore) {
notify($ERRORS{'WARNING'}, 0, "failed to create semaphore object");
return;
}
- # Attempt to open and exclusively lock the file
- if ($semaphore->get_lockfile($semaphore_id, $total_wait_seconds, $attempt_delay_seconds)) {
- # Return the semaphore object
- my $address = sprintf('%x', $semaphore);
- notify($ERRORS{'DEBUG'}, 0, "created '$semaphore_id' Semaphore object, memory address: $address");
+ my $semaphore_object_address = sprintf('%x', $semaphore);
+
+ if ($semaphore->obtain($semaphore_identifier, $semaphore_expire_seconds, $attempt_delay_seconds)) {
+ notify($ERRORS{'DEBUG'}, 0, "obtained semaphore with identifier: '$semaphore_identifier', memory address: $semaphore_object_address");
return $semaphore;
}
else {
- notify($ERRORS{'DEBUG'}, 0, "failed to create '$semaphore_id' Semaphore object");
+ notify($ERRORS{'DEBUG'}, 0, "failed to obtain semaphore with identifier: '$semaphore_identifier'");
return;
}
}
#/////////////////////////////////////////////////////////////////////////////
-
-=head2 does_semaphore_exist
-
- Parameters : $semaphore_id
- Returns : boolean
- Description : Determines if an open Semaphore exists on this management node
- matching the $semaphore_id.
-
-=cut
-
-sub does_semaphore_exist {
- my $self = shift;
- unless (ref($self) && $self->isa('VCL::Module')) {
- notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
- return;
- }
-
- my ($semaphore_id) = @_;
- if (!$semaphore_id) {
- notify($ERRORS{'WARNING'}, 0, "semaphore ID argument was not supplied");
- return;
- }
-
- # Attempt to create a new semaphore object
- my $semaphore = VCL::Module::Semaphore->new({'data_structure' => $self->data, mn_os => $self->mn_os});
- if (!$semaphore) {
- notify($ERRORS{'WARNING'}, 0, "failed to create semaphore object");
- return;
- }
-
- return $semaphore->semaphore_exists($semaphore_id);
-}
-
-#/////////////////////////////////////////////////////////////////////////////
=head2 set_admin_message_variable
Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm?rev=1787209&r1=1787208&r2=1787209&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm Thu Mar 16 15:37:32 2017
@@ -3519,7 +3519,7 @@ sub get_network_bridge_info {
$self->{network_bridge_info} = {};
return $self->{network_bridge_info};
}
- elsif ($exit_status ne '0') {
+ elsif ($exit_status > 0) {
notify($ERRORS{'WARNING'}, 0, "failed to retrieve network bridge configuration from $computer_name, exit status: $exit_status, command:\n$command\noutput:\n" . join("\n", @$output));
return;
}
Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/ManagementNode.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/ManagementNode.pm?rev=1787209&r1=1787208&r2=1787209&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/ManagementNode.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/ManagementNode.pm Thu Mar 16 15:37:32 2017
@@ -383,14 +383,13 @@ sub delete_management_node_reservation_i
configure something such as a storage unit or firewall device
specifically for each reservation.
- The stage argument may be any of the
- following:
- -pre_capture
- -post_capture
- -post_load
- -post_reserve
- -post_initial_connection
- -post_reservation
+ The stage argument may be any of the following:
+ * pre_capture
+ * post_capture
+ * post_load
+ * post_reserve
+ * post_initial_connection
+ * post_reservation
The scripts are stored on the management node under:
/usr/local/vcl/tools/mn_stage_scripts
Modified: vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm?rev=1787209&r1=1787208&r2=1787209&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm Thu Mar 16 15:37:32 2017
@@ -594,7 +594,7 @@ sub load {
my $computer_name = $self->data->get_computer_short_name() || return;
my $image_name = $self->data->get_image_name() || return;
my $vmhost_name = $self->data->get_vmhost_short_name() || return;
-
+
insertloadlog($reservation_id, $computer_id, "startload", "$computer_name $image_name");
@@ -1995,6 +1995,7 @@ sub prepare_vmdk {
my $host_vmdk_file_path_shared = $self->get_vmdk_file_path_shared() || return;
my $host_vmdk_directory_path_shared = $self->get_vmdk_directory_path_shared() || return;
+ my $request_state_name = $self->data->get_request_state_name(0) || 'unknown';
my $image_name = $self->data->get_image_name() || return;
my $vm_computer_name = $self->data->get_computer_short_name() || return;
my $vmhost_name = $self->data->get_vmhost_short_name() || return;
@@ -2004,31 +2005,28 @@ sub prepare_vmdk {
# Semaphores are created when exclusive access to a file/directory is needed to avoid conflicts
# A semaphore ID is a string identifying a semaphore object when created
# Only 1 process at a time may create a semaphore with a given ID - other processes must wait if they attempt to do so
- # If the VM profile disk type is NOT network, include the VM host name in the semaphore ID
- # This means exclusive access to a directory is only restricted to the same VM host
- # If the disk type is network, multiple VM hosts may use the same directory so access should be restricted across hosts
- my $vmdk_semaphore_id;
- my $shared_vmdk_semaphore_id;
- my $vmprofile_disk_type = $self->data->get_vmhost_profile_vmdisk();
- if ($vmprofile_disk_type =~ /network/i) {
- $vmdk_semaphore_id = $host_vmdk_directory_path;
- $shared_vmdk_semaphore_id = $host_vmdk_directory_path_shared;
- }
- else {
- $vmdk_semaphore_id = "$vmhost_name-$host_vmdk_directory_path";
- $shared_vmdk_semaphore_id = "$vmhost_name-$host_vmdk_directory_path_shared";
- }
# Establish a semaphore for the shared vmdk directory before checking if it exists
# This causes this process to wait if another process is copying to the shared directory
# Wait a long time to create the semaphore in case another process is copying a large vmdk to the directory
- my $vmdk_semaphore = $self->get_semaphore($shared_vmdk_semaphore_id, (60 * 20), 5) || return;
- my $shared_vmdk_exists = $self->vmhost_os->file_exists($host_vmdk_file_path_shared);
- # Return 1 if the VM is not dedicated and the shared vmdk already exists on the host
- if ($shared_vmdk_exists && !$is_vm_dedicated) {
- notify($ERRORS{'DEBUG'}, 0, "VM is not dedicated and shared vmdk file already exists on VM host $vmhost_name: $host_vmdk_file_path");
- return 1;
+ my $shared_vmdk_semaphore = $self->get_datastore_directory_semaphore($host_vmdk_directory_path_shared, (60 * 30)) || return;
+
+ my $dedicated_vmdk_semaphore;
+ if ($host_vmdk_directory_path_shared ne $host_vmdk_directory_path) {
+ $dedicated_vmdk_semaphore = $self->get_datastore_directory_semaphore($host_vmdk_directory_path, (60 * 30)) || return;
+ }
+
+ # Return if the VM is not dedicated and the shared vmdk already exists on the host
+ my $shared_vmdk_exists = $self->vmhost_os->file_exists($host_vmdk_file_path_shared);
+ if ($shared_vmdk_exists) {
+ # Release the shared vmdk semaphore - image should be completely copied to correct location
+ undef $shared_vmdk_semaphore;
+
+ if (!$is_vm_dedicated) {
+ notify($ERRORS{'DEBUG'}, 0, "VM is not dedicated and shared vmdk file already exists on VM host $vmhost_name: $host_vmdk_file_path");
+ return 1;
+ }
}
# VM is either:
@@ -2037,32 +2035,27 @@ sub prepare_vmdk {
# -vmdk directory should be created and vmdk files copied to it
# -shared and the directory doesn't exist
# -shared vmdk directory should be retrieved from the image repository
- # Update the semaphore for exclusive access to the vmdk directory if this is not the same directory as the shared directory
- # The original semaphore is automatically released when the variable is reassigned
- if ($vmdk_semaphore_id ne $shared_vmdk_semaphore_id) {
- $vmdk_semaphore = $self->get_semaphore($vmdk_semaphore_id, (60 * 1)) || return;
- }
+
# If the VM is dedicated, check if the dedicated vmdk already exists on the host, delete it if necessary
- if ($is_vm_dedicated && $self->vmhost_os->file_exists($host_vmdk_directory_path)) {
- my $request_state_name = $self->data->get_request_state_name(0);
- if ($request_state_name && $request_state_name =~ /(new|reload)/) {
- notify($ERRORS{'WARNING'}, 0, "VM is dedicated and vmdk directory already exists on VM host $vmhost_name: $host_vmdk_directory_path, existing directory will be deleted");
- if (!$self->vmhost_os->delete_file($host_vmdk_directory_path)) {
- notify($ERRORS{'WARNING'}, 0, "failed to delete existing dedicated vmdk directory on VM host $vmhost_name: $host_vmdk_directory_path");
- return;
+ if ($is_vm_dedicated) {
+ if ($self->vmhost_os->file_exists($host_vmdk_directory_path)) {
+ if ($request_state_name =~ /(new|reload)/) {
+ notify($ERRORS{'WARNING'}, 0, "VM is dedicated and vmdk directory already exists on VM host $vmhost_name: $host_vmdk_directory_path, existing directory will be deleted");
+ if (!$self->vmhost_os->delete_file($host_vmdk_directory_path)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to delete existing dedicated vmdk directory on VM host $vmhost_name: $host_vmdk_directory_path");
+ return;
+ }
+ }
+ else {
+ # Don't delete the directory, it may be in use by a VM
+ # Attempting to delete it will likely delete some files but not all, leaving a mess to reconstruct
+ notify($ERRORS{'OK'}, 0, "VM is dedicated and vmdk directory already exists on VM host $vmhost_name: $host_vmdk_directory_path, request state is not new or reload, directory will not be deleted, returning true");
+ return 1;
}
}
- else {
- # Don't delete the directory, it may be in use by a VM
- # Attempting to delete it will likely delete some files but not all, leaving a mess to reconstruct
- notify($ERRORS{'OK'}, 0, "VM is dedicated and vmdk directory already exists on VM host $vmhost_name: $host_vmdk_directory_path, request state is not new or reload, directory will not be deleted, returning true");
- return 1;
- }
- }
-
- # Check if the VM is dedicated, if so, attempt to copy files from the shared vmdk directory if it exists
- if ($is_vm_dedicated) {
+
+ # Attempt to copy files from the shared vmdk directory if it exists
if ($shared_vmdk_exists) {
notify($ERRORS{'DEBUG'}, 0, "VM is dedicated and shared vmdk exists on the VM host $vmhost_name, attempting to make a copy");
if ($self->copy_vmdk($host_vmdk_file_path_shared, $host_vmdk_file_path)) {
@@ -4922,7 +4915,7 @@ sub get_vm_os_configuration {
my $image_os_name = $self->data->get_image_os_name() || return;
my $image_os_type = $self->data->get_image_os_type();
my $image_architecture = $self->data->get_image_architecture() || return;
-
+
# Figure out the key name in the %VM_OS_CONFIGURATION hash for the guest OS
for my $vm_os_configuration_key (keys(%VM_OS_CONFIGURATION)) {
my ($os_product_name, $os_architecture) = $vm_os_configuration_key =~ /(.+)-(.+)/;
@@ -5457,7 +5450,7 @@ sub get_vmx_info {
next;
}
elsif ($vmdk_file_path !~ /\.vmdk$/i) {
- notify($ERRORS{'DEBUG'}, 0, "ignoring $storage_identifier, filename property does not end with .vmdk: $vmdk_file_path");
+ notify($ERRORS{'DEBUG'}, 0, "ignoring $storage_identifier, filename property does not end with .vmdk: $vmdk_file_path\n" . format_data($vmx_info{vmdk}{$storage_identifier}));
delete $vmx_info{vmdk}{$storage_identifier};
next;
}
@@ -9995,6 +9988,72 @@ sub migrate_revert_source {
}
}
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_datastore_directory_semaphore
+
+ Parameters : $path, $total_wait_seconds (optional)
+ Returns : VCL::Module::Semaphore object, false, or undefined
+ Description : Obtains a semaphore for exclusive access to the directory on the
+ datastore.
+
+=cut
+
+sub get_datastore_directory_semaphore {
+ my $self = shift;
+ if (ref($self) !~ /vmware/i) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ return;
+ }
+
+ my ($datastore_directory_path, $total_wait_seconds) = @_;
+ if (!defined($datastore_directory_path)) {
+ notify($ERRORS{'WARNING'}, 0, "datastore directory path argument was not supplied");
+ return;
+ }
+
+ $total_wait_seconds = 300 unless $total_wait_seconds;
+
+ notify($ERRORS{'DEBUG'}, 0, "attempting to obtain semaphore for datastore directory: $datastore_directory_path");
+
+ my $datastore_url = $self->_get_datastore_url($datastore_directory_path);
+ if (!$datastore_url) {
+ notify($ERRORS{'WARNING'}, 0, "failed to obtain semaphore, datastore URL could not be determined for path: $datastore_directory_path");
+ return;
+ }
+ notify($ERRORS{'DEBUG'}, 0, "determined datastore URL: $datastore_url");
+
+ my $directory_name;
+ if ($datastore_directory_path =~ /\.[^\/]+$/) {
+ # Argument appears to be a file path, use the parent directory name
+ $directory_name = $self->_get_parent_directory_name($datastore_directory_path);
+ if (!$directory_name) {
+ notify($ERRORS{'WARNING'}, 0, "failed to obtain semaphore, argument appears to be a file path: $datastore_directory_path, parent directory name could not be determined");
+ return;
+ }
+ notify($ERRORS{'DEBUG'}, 0, "argument appears to be a file path: $datastore_directory_path, using parent directory name for semaphore ID: $directory_name");
+ }
+ else {
+ $directory_name = $self->_get_file_base_name($datastore_directory_path);
+ if (!$directory_name) {
+ notify($ERRORS{'WARNING'}, 0, "failed to obtain semaphore, argument appears to be a directory path: $datastore_directory_path, base name could not be determined");
+ return;
+ }
+ notify($ERRORS{'DEBUG'}, 0, "argument appears to be a directory path: $datastore_directory_path, using directory name for semaphore ID: $directory_name");
+ }
+
+ my $semaphore_identifier = $datastore_url . '/' . $directory_name;
+ my $semaphore = $self->get_semaphore($semaphore_identifier, $total_wait_seconds);
+ if ($semaphore) {
+ notify($ERRORS{'DEBUG'}, 0, "obtained semaphore with identifier '$semaphore_identifier', returning semaphore object");
+ return $semaphore;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to obtain semaphore with identifier '$semaphore_identifier', returning 0");
+ return 0;
+ }
+}
+
#/////////////////////////////////////////////////////////////////////////////
1;
Modified: vcl/trunk/managementnode/lib/VCL/Module/Semaphore.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/Semaphore.pm?rev=1787209&r1=1787208&r2=1787209&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/Semaphore.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/Semaphore.pm Thu Mar 16 15:37:32 2017
@@ -25,7 +25,7 @@ VCL::Module::Semaphore - VCL module to c
=head1 SYNOPSIS
my $semaphore = VCL::Module::Semaphore->new({data_structure => $self->data});
- $semaphore->get_lockfile($semaphore_id, $total_wait_seconds, $attempt_delay_seconds);
+ $semaphore->obtain('something-unique', 240, $3);
=head1 DESCRIPTION
@@ -67,478 +67,123 @@ use VCL::utils;
##############################################################################
-=head1 CLASS VARIABLES
-
-=cut
-
-=head2 $LOCKFILE_DIRECTORY_PATH
-
- Data type : String
- Description : Location on the management node of the lockfiles are stored.
-
-=cut
-
-our $LOCKFILE_DIRECTORY_PATH = "/tmp";
-
-=head2 $LOCKFILE_EXTENSION
-
- Data type : String
- Description : File extension to be used for lockfiles.
-
-=cut
-
-our $LOCKFILE_EXTENSION = "semaphore";
-
-##############################################################################
-
=head1 OBJECT METHODS
=cut
#/////////////////////////////////////////////////////////////////////////////
-=head2 get_lockfile
+=head2 obtain
- Parameters : $semaphore_id, $total_wait_seconds (optional), $attempt_delay_seconds (optional)
- Returns : filehandle
- Description : Attempts to open and obtain an exclusive lock on the file
- specified by the file path argument. If unable to obtain an
- exclusive lock, it will wait up to the value specified by the
- total wait seconds argument (default: 30 seconds). The number of
- seconds to wait in between retries can be specified (default: 15
- seconds).
+ Parameters : $semaphore_identifier, $semaphore_expire_seconds (optional), $attempt_delay_seconds (optional)
+ Returns : string
+ Description : Obtains a semaphore by inserting a row into the vcldsemaphore
+ database table.
+
+ The $semaphore_expire_seconds is used to both determine when the
+ semaphore should be considered orphaned and to determine how long
+ the current process attempts to obtain a semaphore if blocked by
+ another process.
=cut
-sub get_lockfile {
+sub obtain {
my $self = shift;
unless (ref($self) && $self->isa('VCL::Module')) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
- # Get the semaphore ID argument
- my ($semaphore_id, $total_wait_seconds, $attempt_delay_seconds) = @_;
- if (!$semaphore_id) {
- notify($ERRORS{'WARNING'}, 0, "semaphore ID argument was not supplied");
- return;
- }
-
- $semaphore_id =~ s/\W+/-/g;
- $semaphore_id =~ s/(^-|-$)//g;
-
- my $file_path = "$LOCKFILE_DIRECTORY_PATH/$semaphore_id.$LOCKFILE_EXTENSION";
-
- # Set the wait defaults if not supplied as arguments
- $total_wait_seconds = 30 if !defined($total_wait_seconds);
- $attempt_delay_seconds = 5 if !$attempt_delay_seconds;
-
- # Attempt to lock the file
- my $wait_message = "attempting to open lockfile";
- if ($self->code_loop_timeout(\&open_lockfile, [$self, $file_path], $wait_message, $total_wait_seconds, $attempt_delay_seconds)) {
- return $file_path;
- }
- else {
- notify($ERRORS{'DEBUG'}, 0, "failed to open lockfile: $file_path");
- return;
- }
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 open_lockfile
-
- Parameters : $file_path
- Returns : If successful: IO::File file handle object
- If failed: false
- Description : Opens and obtains an exclusive lock on the file specified by the
- argument.
-
-=cut
-
-sub open_lockfile {
- my $self = shift;
- unless (ref($self) && $self->isa('VCL::Module')) {
- notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ my ($semaphore_identifier, $semaphore_expire_seconds, $attempt_delay_seconds) = @_;
+ if (!$semaphore_identifier) {
+ notify($ERRORS{'WARNING'}, 0, "semaphore identifier argument was not supplied");
return;
}
-
- # Get the file path argument
- my ($file_path) = @_;
- if (!$file_path) {
- notify($ERRORS{'WARNING'}, 0, "file path argument was not supplied");
+ elsif (defined($semaphore_expire_seconds) && $semaphore_expire_seconds !~ /^\d+$/) {
+ notify($ERRORS{'WARNING'}, 0, "semaphore expire seconds argument is not a valid integer: $semaphore_expire_seconds");
return;
}
- # Attempt to open and lock the file
- if (my $file_handle = new IO::File($file_path, O_WRONLY|O_CREAT)) {
- if (flock($file_handle, LOCK_EX | LOCK_NB)) {
- notify($ERRORS{'DEBUG'}, 0, "opened and obtained an exclusive lock on file: $file_path");
-
- # Truncate and print the process information to the file
- $file_handle->truncate(0);
- print $file_handle "$$ $0\n";
- $file_handle->setpos($file_handle->getpos());
-
- notify($ERRORS{'DEBUG'}, 0, "wrote to file: $file_path, contents:\n '$$ $0'");
-
- $self->{file_handles}{$file_path} = $file_handle;
- return $file_handle;
- }
- else {
- notify($ERRORS{'DEBUG'}, 0, "unable to obtain exclusive lock on file: $file_path");
- $file_handle->close;
- }
- }
- else {
- notify($ERRORS{'WARNING'}, 0, "failed to open file: $file_path, error:\n$!");
- return;
- }
-
- # Don't use get_lockfile_owning_pid or anything that uses lsof on the management node
- # Not safe - seems to send ALRM some time after command seems to have run
- ## Determine which process is locking the file
- #my @locking_pids = $self->get_lockfile_owning_pid($file_path);
- #if (@locking_pids) {
- # if (grep { $_ eq $PID } @locking_pids) {
- # # The current process already has an exclusive lock on the file
- # # This could happen if open_lockfile is called more than once for the same file in the same scope
- # notify($ERRORS{'WARNING'}, 0, "file is already locked by this process: @locking_pids");
- # return;
- # }
- # else {
- # # Attempt to retrieve the names of the locking process(es)
- # my ($ps_exit_status, $ps_output) = run_command("ps -o pid=,cmd= @locking_pids", 1);
- # if (defined($ps_output) && !grep(/(ps:)/, @$ps_output)) {
- # notify($ERRORS{'DEBUG'}, 0, "file is locked by another process: @locking_pids\n" . join("\n", @$ps_output));
- # }
- # else {
- # notify($ERRORS{'DEBUG'}, 0, "file is locked by another process: @locking_pids");
- # }
- # return;
- # }
- #}
- #else {
- # notify($ERRORS{'DEBUG'}, 0, "unable to determine PIDs of processes which prevented an exclusive lock to be obtained on $file_path, lock may have been released before lsof command was executed");
- #}
-
- return;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-#
-#=head2 get_lockfile_owning_pid
-#
-# Parameters : $file_path
-# Returns : integer
-# Description : Runs lsof to determine if a process has an exclusive lock on the
-# lockfile.
-#
-#=cut
-#
-#sub get_lockfile_owning_pid {
-# my $self = shift;
-# unless (ref($self) && $self->isa('VCL::Module')) {
-# notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
-# return;
-# }
-#
-# # Get the file path argument
-# my ($file_path) = @_;
-# if (!$file_path) {
-# notify($ERRORS{'WARNING'}, 0, "file path argument was not supplied");
-# return;
-# }
-#
-# # Run lsof to determine which process is locking the file
-# #my ($exit_status, $output) = $self->mn_os->execute("/usr/sbin/lsof -S 2 -O -Fp $file_path", 1, 10);
-# my ($exit_status, $output) = $self->mn_os->execute("/usr/sbin/lsof -Fp $file_path", 0, 10);
-# if (!defined($output)) {
-# notify($ERRORS{'WARNING'}, 0, "failed to run lsof command to determine which process is locking the file: $file_path");
-# return;
-# }
-# elsif (grep(/no such file/i, @$output)) {
-# notify($ERRORS{'WARNING'}, 0, "lsof command reports that the file does not exist: $file_path");
-# return;
-# }
-#
-# # Parse the lsof output to determine the PID
-# my @locking_pids = map { /^p(\d+)/ } @$output;
-# my $locking_pid_count = scalar(@locking_pids);
-# if (@locking_pids) {
-# notify($ERRORS{'DEBUG'}, 0, "$file_path is locked by process" . ($locking_pid_count == 1 ? '' : 'es') . ": @locking_pids");
-# return @locking_pids;
-# }
-# elsif (grep(/\w/, @$output)) {
-# notify($ERRORS{'WARNING'}, 0, "failed to determine owning PID of lockfile: $file_path, unable to determine PIDs from lsof output\n:" . join("\n", @$output));
-# return;
-# }
-# else {
-# notify($ERRORS{'DEBUG'}, 0, "file is not locked: $file_path");
-# return ();
-# }
-#}
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 release_lockfile
-
- Parameters : $file_path
- Returns : boolean
- Description : Releases the exclusive lock and closes the lockfile handle
- specified by the argument.
-
-=cut
-
-sub release_lockfile {
- my $self = shift;
- unless (ref($self) && $self->isa('VCL::Module')) {
- notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
- return;
- }
-
- # Get the file path argument
- my $file_path = shift;
- if (!$file_path) {
- notify($ERRORS{'WARNING'}, 0, "file path argument was not supplied");
- return;
- }
-
- my $file_handle = $self->{file_handles}{$file_path};
- if (!$file_handle) {
- notify($ERRORS{'WARNING'}, 0, "file handle is not saved in this object for file path: $file_path");
- return;
- }
-
- # Make sure the file handle is opened
- my $fileno = $file_handle->fileno;
- if (!$fileno) {
- notify($ERRORS{'WARNING'}, 0, "file is not opened: $file_path");
- }
-
- if (!flock($file_handle, LOCK_UN)) {
- notify($ERRORS{'WARNING'}, 0, "failed to unlock file: $file_path, reason: $!");
- }
-
- # Close the file
- if (!close($file_handle)) {
- notify($ERRORS{'WARNING'}, 0, "failed to close file: $file_path, reason: $!");
- }
+ $semaphore_expire_seconds = 300 unless defined($semaphore_expire_seconds);
+ $attempt_delay_seconds = 5 if !$attempt_delay_seconds;
- # Delete the file
- if (unlink($file_path)) {
- notify($ERRORS{'DEBUG'}, 0, "deleted file: $file_path");
+ # Attempt to set the variable
+ my $wait_message = "attempting to add a row to the vcldsemaphore table with identifier: '$semaphore_identifier'";
+ if ($self->code_loop_timeout(\&_obtain, [$self, $semaphore_identifier, $semaphore_expire_seconds], $wait_message, $semaphore_expire_seconds, $attempt_delay_seconds)) {
+ notify($ERRORS{'OK'}, 0, "*** created semaphore by adding a row to the vcldsemaphore table with identifier: '$semaphore_identifier' ***");
+ $self->{vcldsemaphore_table_identifiers}{$semaphore_identifier} = 1;
+ return 1;
}
else {
- notify($ERRORS{'WARNING'}, 0, "failed to delete file: $file_path, reason: $!");
- }
-
- delete $self->{file_handles}{$file_path};
- return 1;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 get_lockfile_paths
-
- Parameters : none
- Returns : array
- Description : Returns the paths to all lockfiles.
-
-=cut
-
-sub get_lockfile_paths {
- my $self = shift;
- unless (ref($self) && $self->isa('VCL::Module')) {
- notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+ notify($ERRORS{'WARNING'}, 0, "failed to obtain semaphore by adding a row to the vcldsemaphore table after attempting for $semaphore_expire_seconds seconds: '$semaphore_identifier'");
return;
}
-
- my @lockfile_paths = $self->mn_os->find_files($LOCKFILE_DIRECTORY_PATH, "*.$LOCKFILE_EXTENSION");
-
- my $lockfile_path_count = scalar(@lockfile_paths);
- notify($ERRORS{'DEBUG'}, 0, "retreived $lockfile_path_count lockfile path" . ($lockfile_path_count == 1 ? '' : 's') . ":\n" . join("\n", @lockfile_paths));
- return @lockfile_paths;
}
#/////////////////////////////////////////////////////////////////////////////
-=head2 semaphore_exists
+=head2 _obtain
- Parameters : $semaphore_id
+ Parameters : $semaphore_identifier, $semaphore_expire_seconds
Returns : boolean
- Description : Determines if an open Semaphore exists on this management node
- matching the $semaphore_id.
+ Description : Helper function for Semaphore.pm::obtain. Attempts to call
+ insert_vcld_semaphore. If this fails, it retrieves existing
+ vcldsemaphore table entries and deletes expired rows.
=cut
-sub semaphore_exists {
+sub _obtain {
my $self = shift;
unless (ref($self) && $self->isa('VCL::Module')) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
- my ($semaphore_id) = @_;
- if (!$semaphore_id) {
- notify($ERRORS{'WARNING'}, 0, "semaphore ID argument was not supplied");
- return;
- }
-
- my @lockfile_paths = $self->get_lockfile_paths();
- if (!@lockfile_paths) {
- notify($ERRORS{'DEBUG'}, 0, "did not find any lockfiles on this management node");
- return ();
- }
+ my ($semaphore_identifier, $semaphore_expire_seconds) = @_;
- for my $lockfile_path (@lockfile_paths) {
- my ($lockfile_semaphore_id) = $lockfile_path =~ /([^\/]+)\.$LOCKFILE_EXTENSION/;
- if ($lockfile_semaphore_id ne $semaphore_id) {
- next;
- }
-
- # Check if the lockfile is actually locked by another process
- # It may have been released or deleted
- my @lockfile_owning_pids = $self->get_lockfile_owning_pid($lockfile_path);
- if (@lockfile_owning_pids) {
- notify($ERRORS{'DEBUG'}, 0, "'$semaphore_id' semaphore exists, lockfile path: $lockfile_path, owning PID: @lockfile_owning_pids");
- return 1;
- }
- else {
- notify($ERRORS{'DEBUG'}, 0, "ignoring lockfile not locked by another process: $lockfile_path");
- next;
- }
- }
+ my $reservation_id = $self->data->get_reservation_id();
- notify($ERRORS{'DEBUG'}, 0, "'$semaphore_id' semaphore does not exist");
- return 0;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 get_reservation_semaphore_ids
-
- Parameters : $reservation_id
- Returns : array
- Description : Returns the Semaphore IDs opened by the reservation specified by
- the argument. An empty list is returned if no Semaphores are
- open.
-
-=cut
-
-sub get_reservation_semaphore_ids {
- my $self = shift;
- unless (ref($self) && $self->isa('VCL::Module')) {
- notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
- return;
+ if (insert_vcld_semaphore($semaphore_identifier, $reservation_id, $semaphore_expire_seconds)) {
+ return 1;
}
- my $reservation_id = shift || $self->data->get_reservation_id();
- if (!$reservation_id) {
- notify($ERRORS{'WARNING'}, 0, "reservation ID argument was not supplied");
- return;
- }
+ my $current_datetime = makedatestring();
+ my $current_epoch = convert_to_epoch_seconds($current_datetime);
- my @lockfile_paths = $self->get_lockfile_paths();
- if (!@lockfile_paths) {
- notify($ERRORS{'DEBUG'}, 0, "did not find any lockfiles on this management node");
- return ();
- }
-
- my @reservation_semaphore_ids;
- for my $lockfile_path (@lockfile_paths) {
- my ($semaphore_id) = $lockfile_path =~ /([^\/]+)\.$LOCKFILE_EXTENSION/;
-
- my @lockfile_contents = $self->mn_os->get_file_contents($lockfile_path);
- if (!@lockfile_contents) {
- notify($ERRORS{'WARNING'}, 0, "failed to retrieve contents of lockfile: $lockfile_path");
+ my $semaphore_info = get_vcld_semaphore_info();
+ for my $existing_semaphore_identifier (keys %$semaphore_info) {
+ # Ignore if identifier is different
+ if ($existing_semaphore_identifier ne $semaphore_identifier) {
next;
}
- my $lockfile_line = $lockfile_contents[0];
+ my $existing_reservation_id = $semaphore_info->{$existing_semaphore_identifier}{reservationid};
+ my $existing_expires_datetime = $semaphore_info->{$existing_semaphore_identifier}{expires};
+ my $existing_expires_epoch = convert_to_epoch_seconds($existing_expires_datetime);
- # Line should contain a string similar to this:
- # 31862 vclark 2376:3116 tomaintenance vclv1-42>vclh3-12.hpc.ncsu.edu vmwarewinxp-base234-v14 admin
- my ($lockfile_reservation_id) = $lockfile_line =~ / \d+:(\d+) /;
-
- if (!defined($lockfile_reservation_id)) {
- notify($ERRORS{'WARNING'}, 0, "failed to determine reservation ID from 1st line in $lockfile_path: '$lockfile_line'");
- next;
+ # Make sure existing semaphore wasn't created for this reservation - this should never happen
+ if ($existing_reservation_id eq $reservation_id) {
+ notify($ERRORS{'WARNING'}, 0, "semaphore with same identifier already exists for this reservation: $existing_semaphore_identifier, attempting to forcefully update existing vclsemaphore entry:\n" . format_data($semaphore_info->{$existing_semaphore_identifier}));
+ if (insert_vcld_semaphore($semaphore_identifier, $reservation_id, $semaphore_expire_seconds, 1)) {
+ return 1;
+ }
}
- if ($lockfile_reservation_id == $reservation_id) {
- notify($ERRORS{'DEBUG'}, 0, "semaphore '$semaphore_id' belongs to reservation $reservation_id");
- push @reservation_semaphore_ids, $semaphore_id;
+ if ($existing_expires_epoch < $current_epoch) {
+ notify($ERRORS{'WARNING'}, 0, "attempting to delete expired vcldsemaphore table entry:\n" .
+ "current time: $current_datetime ($current_epoch)\n" .
+ "expire time: $existing_expires_datetime ($existing_expires_epoch)"
+ );
+ delete_vcld_semaphore($existing_semaphore_identifier, $existing_expires_datetime);
}
else {
- notify($ERRORS{'DEBUG'}, 0, "semaphore '$semaphore_id' does NOT belong to reservation $reservation_id");
+ notify($ERRORS{'DEBUG'}, 0, "existing vcldsemaphore table entry has NOT expired:\n" .
+ "current time: $current_datetime ($current_epoch)\n" .
+ "expire time: $existing_expires_datetime ($existing_expires_epoch)"
+ );
}
}
- return @reservation_semaphore_ids;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 get_process_semaphore_ids
-
- Parameters : $pid
- Returns : array
- Description : Returns the Semaphore IDs opened by the process PID specified by
- the argument. An empty list is returned if no Semaphores are
- open.
-
-=cut
-
-sub get_process_semaphore_ids {
- my $self = shift;
- unless (ref($self) && $self->isa('VCL::Module')) {
- notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
- return;
- }
-
- my $pid = shift;
- if (!$pid) {
- notify($ERRORS{'WARNING'}, 0, "process PID argument was not supplied");
- return;
- }
-
- my @lockfile_paths = $self->get_lockfile_paths();
- if (!@lockfile_paths) {
- notify($ERRORS{'DEBUG'}, 0, "did not find any lockfiles on this management node");
- return ();
- }
-
- my @process_semaphore_ids;
-
- for my $lockfile_path (@lockfile_paths) {
- my ($semaphore_id) = $lockfile_path =~ /([^\/]+)\.$LOCKFILE_EXTENSION/;
-
- my @lockfile_contents = $self->mn_os->get_file_contents($lockfile_path);
- if (!@lockfile_contents) {
- notify($ERRORS{'WARNING'}, 0, "failed to retrieve contents of lockfile: $lockfile_path");
- next;
- }
-
- my $lockfile_line = $lockfile_contents[0];
-
- # Line should contain a string similar to this:
- # 31862 vclark 2376:3116 tomaintenance vclv1-42>vclh3-12.hpc.ncsu.edu vmwarewinxp-base234-v14 admin
- my ($lockfile_pid) = $lockfile_line =~ /^(\d+) /;
-
- if (!defined($lockfile_pid)) {
- notify($ERRORS{'WARNING'}, 0, "failed to determine PID from 1st line in $lockfile_path: '$lockfile_line'");
- next;
- }
-
- if ($lockfile_pid == $pid) {
- notify($ERRORS{'DEBUG'}, 0, "semaphore '$semaphore_id' belongs to process $pid");
- push @process_semaphore_ids, $semaphore_id;
- }
- else {
- notify($ERRORS{'DEBUG'}, 0, "semaphore '$semaphore_id' does NOT belong to process $pid");
- }
- }
- return @process_semaphore_ids;
+ return 0;
}
#/////////////////////////////////////////////////////////////////////////////
@@ -547,8 +192,8 @@ sub get_process_semaphore_ids {
Parameters : none
Returns : nothing
- Description : Destroys the semaphore object. The files opened and exclusively
- locked by the semaphore object are closed and deleted.
+ Description : Destroys the semaphore object. Database vcldsemaphore table
+ entries created for this object are deleted.
=cut
@@ -556,8 +201,8 @@ sub DESTROY {
my $self = shift;
my $address = sprintf('%x', $self);
- for my $file_path (keys %{$self->{file_handles}}) {
- $self->release_lockfile($file_path);
+ for my $semaphore_identifier (keys %{$self->{vcldsemaphore_table_identifiers}}) {
+ delete_vcld_semaphore($semaphore_identifier);
}
# Check for an overridden destructor
Modified: vcl/trunk/managementnode/lib/VCL/new.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/new.pm?rev=1787209&r1=1787208&r2=1787209&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/new.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/new.pm Thu Mar 16 15:37:32 2017
@@ -788,14 +788,16 @@ sub computer_not_being_used {
if (my @competing_reservation_pids = reservation_being_processed($competing_reservation_id)) {
notify($ERRORS{'OK'}, 0, "reservation $competing_reservation_id is currently being processed by PID(s): " . join(', ', @competing_reservation_pids) . ", making sure the process doesn't have any Semaphore objects open before attempting to kill it");
- # Create a Semaphore object and check if the competing process owns any of its own Semaphore objects
+ # Check if the competing process owns any semaphores
# This would indicate it's doing something such as retrieving an image
# Don't kill it or a partial image may be copied
- my $semaphore = VCL::Module::Semaphore->new();
- for my $competing_reservation_pid (@competing_reservation_pids) {
- if ($semaphore->get_process_semaphore_ids($competing_reservation_pid)) {
- notify($ERRORS{'CRITICAL'}, 0, "computer $computer_short_name is NOT available, reservation $competing_reservation_id is still being processed and owns a Semaphore object, not killing the competing process, it may be transferring an image:\n$competing_request_info_string");
- return;
+ my $semaphore_info = get_vcld_semaphore_info();
+ for my $semaphore_identifier (keys %$semaphore_info) {
+ for my $competing_reservation_pid (@competing_reservation_pids) {
+ if ($semaphore_info->{$semaphore_identifier}{reservationid} == $competing_reservation_id && $semaphore_info->{$semaphore_identifier}{pid} == $competing_reservation_pid) {
+ notify($ERRORS{'CRITICAL'}, 0, "computer $computer_short_name is NOT available, reservation $competing_reservation_id is still being processed and owns a semaphore with identifier '$semaphore_identifier', not killing the competing process, it may be transferring an image:\n$competing_request_info_string, semaphore info:\n" . format_data($semaphore_info->{$semaphore_identifier}));
+ return;
+ }
}
}