~vcs-imports/mogilefs/trunk

« back to all changes in this revision

Viewing changes to server/lib/Mogstored/ChildProcess/DiskUsage.pm

  • Committer: hachi
  • Date: 2011-05-27 23:40:03 UTC
  • Revision ID: hachi-20110527234003-hioplx58nt6zb2mx
This has been moved to http://github.com/mogilefs/MogileFS-Server/

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package Mogstored::ChildProcess::DiskUsage;
2
 
use strict;
3
 
use base 'Mogstored::ChildProcess';
4
 
 
5
 
my $docroot;
6
 
 
7
 
sub pre_exec_init {
8
 
    my $class = shift;
9
 
    $SIG{TERM} = 'DEFAULT'; # override custom one from earlier
10
 
    $ENV{MOG_DOCROOT} = Perlbal->service('mogstored')->{docroot};
11
 
}
12
 
 
13
 
sub run {
14
 
    $docroot = $ENV{MOG_DOCROOT};
15
 
    die "\$ENV{MOG_DOCROOT} not set"                unless $docroot;
16
 
    die "\$ENV{MOG_DOCROOT} not set to a directory" unless -d $docroot;
17
 
 
18
 
    # (runs in exec'd child process)
19
 
    $0 = "mogstored [diskusage]";
20
 
    select((select(STDOUT), $|++)[0]);
21
 
 
22
 
    my $start_ppid = getppid();
23
 
 
24
 
    # Discover whether or not we have GNU df.
25
 
    my $gnu_df = '';
26
 
    `df -P / 2>/dev/null >/dev/null`;
27
 
    if ($? eq 0) {
28
 
       $gnu_df = '-P';
29
 
    }
30
 
 
31
 
    while (1) {
32
 
        look_at_disk_usage($gnu_df);
33
 
        sleep 10;
34
 
 
35
 
        # shut ourselves down if our parent mogstored
36
 
        # has gone away.
37
 
        my $ppid = getppid();
38
 
        exit(0) unless $ppid == $start_ppid && kill(0,$ppid);
39
 
    }
40
 
}
41
 
 
42
 
sub look_at_disk_usage {
43
 
    my $err = sub { warn "$_[0]\n"; };
44
 
    my $path = $ENV{MOG_DOCROOT};
45
 
    $path =~ s!/$!!;
46
 
    my $gnu_df = shift;
47
 
 
48
 
    # find all devices below us
49
 
    my @devnum;
50
 
    if (opendir(D, $path)) {
51
 
        @devnum = grep { /^dev\d+$/ } readdir(D);
52
 
        closedir(D);
53
 
    } else {
54
 
        return $err->("Failed to open $path: $!");
55
 
    }
56
 
 
57
 
    foreach my $devnum (@devnum) {
58
 
        my $rval = `df $gnu_df -l -k $path/$devnum`;
59
 
        my $uperK = ($rval =~ /512-blocks/i) ? 2 : 1; # units per kB
60
 
        foreach my $l (split /\r?\n/, $rval) {
61
 
            next unless $l =~ /^(.+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(.+)\s+(.+)$/;
62
 
            my ($dev, $total, $used, $avail, $useper, $disk) = ($1, $2, $3, $4, $5, $6);
63
 
 
64
 
            unless ($disk =~ m!$devnum/?$!) {
65
 
                $disk = "$path/$devnum";
66
 
            }
67
 
 
68
 
            # FIXME: We're stupidly throwing away the 'avail' value here.
69
 
            # This causes mogilefs to run aground when used with ext
70
 
            # partitions using reserved space. Drop the reserved space from
71
 
            # the total, and in the future add available to the device table
72
 
            # and just use that.
73
 
            $total = $used + $avail;
74
 
 
75
 
            # create string to print
76
 
            my $now = time;
77
 
            my $output = {
78
 
                time      => time(),
79
 
                device    => $dev,    # /dev/sdh1
80
 
                total     => int($total / $uperK), # integer: total KiB blocks
81
 
                used      => int($used  / $uperK), # integer: used KiB blocks
82
 
                available => int($avail / $uperK),  # integer: available KiB blocks
83
 
                'use'     => $useper, # "45%"
84
 
                disk      => $disk,   # mount point of disk (/var/mogdata/dev8), or path if not a mount
85
 
            };
86
 
 
87
 
            if ($ENV{MOG_DEV_USAGE_VIA_DU}) {
88
 
                my $size = `du -k -c -s $path/$devnum`;
89
 
                if ($size =~ /^(\d+)/) {
90
 
                    $output->{used} = $1;
91
 
                }
92
 
            }
93
 
 
94
 
            # size of old file we'll be overwriting in place (we'll want
95
 
            # to pad with newlines/spaces, before we truncate it, for
96
 
            # minimizing races)
97
 
            my $ufile    = "$disk/usage";
98
 
            my $old_size = (-s $ufile) || 0;
99
 
            my $mode     = $old_size ? "+<" : ">";
100
 
 
101
 
            # string we'll be writing
102
 
            my $new_data = "";
103
 
            foreach (sort keys %$output) {
104
 
                $new_data .= "$_: $output->{$_}\n";
105
 
            }
106
 
 
107
 
            my $new_size = length $new_data;
108
 
            my $pad_len  = $old_size > $new_size ? ($old_size - $new_size) : 0;
109
 
            $new_data   .= "\n" x $pad_len;
110
 
 
111
 
            # write the file, all at once (with padding) then remove padding
112
 
            my $rv = open(my $fh, $mode, $ufile);
113
 
            unless ($rv) {
114
 
                $err->("Unable to open '$ufile' for writing: $!");
115
 
                next;
116
 
            }
117
 
            unless (syswrite($fh, $new_data)) {
118
 
                close($fh);
119
 
                $err->("Error writing to '$ufile': $!");
120
 
                next;
121
 
            }
122
 
            truncate($fh, $new_size) if $pad_len;
123
 
            close($fh);
124
 
        }
125
 
    }
126
 
}
127
 
 
128
 
 
129
 
1;