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;
+ }
}
}