Author: arkurth Date: Tue Apr 19 14:33:29 2011 New Revision: 1095103 URL: http://svn.apache.org/viewvc?rev=1095103&view=rev Log: VCL-452 Updated Linux.pm::get_file_size. It now returns the size used on disk by a file which should allow the size of vmdk files to be reported correctly.
Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm?rev=1095103&r1=1095102&r2=1095103&view=diff ============================================================================== --- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm (original) +++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm Tue Apr 19 14:33:29 2011 @@ -1947,10 +1947,21 @@ sub copy_file { =head2 get_file_size Parameters : $file_path - Returns : integer + Returns : integer or array Description : Determines the size of the file specified by the file path - argument in bytes. The file path argument may contain wildcards. - If the path argument is a directory, 0 will be returned. + argument in bytes. The file path argument may be a directory or + contain wildcards. Directories are processed recursively. + + When called in sclar context, the actual bytes used on the disk by the file + is returned. This correlates to the size reported by the `du` + command. This value is not the same as what is reported by the `ls` + command. This is important when determining the size of + compressed files or thinly-provisioned virtual disk images. + + When called in array context, 3 values are returned: + [0] bytes used (`du` size) + [1] bytes reserved (`ls` size) + [2] file count =cut @@ -1961,6 +1972,8 @@ sub get_file_size { return; } + my $calling_sub = (caller(1))[3] || ''; + # Get the path argument my $file_path = shift; if (!$file_path) { @@ -1978,14 +1991,23 @@ sub get_file_size { my $computer_node_name = $self->data->get_computer_node_name() || return; # Run stat rather than du because du is not available on VMware ESX - my $command = 'stat -c "%F:%s:%b:%B:%n" ' . $escaped_file_path; + # -L Dereference links + # %F File type + # %n File name + # %b Number of blocks allocated (see %B) + # %B The size in bytes of each block reported by %b + # %s Total size, in bytes + + my $command = 'stat -L -c "%F:%n:%s:%b:%B" ' . $escaped_file_path; my ($exit_status, $output) = $self->execute($command); if (!defined($output)) { notify($ERRORS{'WARNING'}, 0, "failed to run command to determine file size on $computer_node_name: $file_path\ncommand: '$command'"); return; } elsif (grep(/no such file/i, @$output)) { - notify($ERRORS{'DEBUG'}, 0, "unable to determine size of file on $computer_node_name because it does not exist: $file_path, command: '$command'"); + if ($calling_sub !~ /get_file_size/) { + notify($ERRORS{'DEBUG'}, 0, "unable to determine size of file on $computer_node_name because it does not exist: $file_path\ncommand: '$command'"); + } return; } elsif (grep(/^stat:/i, @$output)) { @@ -1994,11 +2016,12 @@ sub get_file_size { } # Loop through the stat output lines + my $file_count = 0; + my $total_bytes_reserved = 0; my $total_bytes_used = 0; - my $total_bytes_allocated = 0; for my $line (@$output) { # Take the stat output line apart - my ($type, $file_bytes, $file_blocks, $block_size, $path) = split(/:/, $line); + my ($type, $path, $file_bytes, $file_blocks, $block_size) = split(/:/, $line); if (!defined($type) || !defined($file_bytes) || !defined($file_blocks) || !defined($block_size) || !defined($path)) { notify($ERRORS{'WARNING'}, 0, "unexpected output returned from stat, line: $line\ncommand: $command\noutput:\n" . join("\n", @$output)); return; @@ -2006,27 +2029,41 @@ sub get_file_size { # Add the size to the total if the type is file if ($type =~ /file/) { - $total_bytes_allocated += ($file_blocks * $block_size); - $total_bytes_used += $file_bytes; + $file_count++; + + my $file_bytes_allocated = ($file_blocks * $block_size); + + $total_bytes_used += $file_bytes_allocated; + $total_bytes_reserved += $file_bytes; + + #print "$file_count: '$path', used: $file_bytes, allocated: $file_bytes_allocated, ($file_blocks * $block_size)\n"; } elsif ($type =~ /directory/) { $path =~ s/[\\\/\*]+$//g; - notify($ERRORS{'DEBUG'}, 0, "recursively retrieving size of files under directory: '$path'"); - my ($subdirectory_bytes_used, $subdirectory_bytes_allocated) = $self->get_file_size("$path/*"); - $total_bytes_used += $subdirectory_bytes_used; - $total_bytes_allocated += $subdirectory_bytes_allocated; + #notify($ERRORS{'DEBUG'}, 0, "recursively retrieving size of files under directory: '$path'"); + my ($subdirectory_bytes_allocated, $subdirectory_bytes_used, $subdirectory_file_count) = $self->get_file_size("$path/*"); + + # Values will be null if there are no files under the subdirectory + if (!defined($subdirectory_bytes_allocated)) { + next; + } + + $file_count += $subdirectory_file_count; + $total_bytes_reserved += $subdirectory_bytes_used; + $total_bytes_used += $subdirectory_bytes_allocated; } } my $calling_sub = (caller(1))[3] || ''; if ($calling_sub !~ /get_file_size/) { notify($ERRORS{'DEBUG'}, 0, "size of '$file_path' on $computer_node_name:\n" . - "used: " . get_file_size_info_string($total_bytes_used) . "\n" . - "allocated: " . get_file_size_info_string($total_bytes_allocated)); + "file count: $file_count\n" . + "reserved: " . get_file_size_info_string($total_bytes_reserved) . "\n" . + "used: " . get_file_size_info_string($total_bytes_used)); } if (wantarray) { - return ($total_bytes_used, $total_bytes_allocated); + return ($total_bytes_used, $total_bytes_reserved, $file_count); } else { return $total_bytes_used;