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