blob: 0c67370107843a3333d6f02fa428079b9f224d20 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#!/usr/bin/ruby
require 'sys/filesystem'
module Byteback
class DiskFreeReading < Struct.new(:fsstat, :time)
def initialize(fsstat, time = Time.now)
self.fsstat = fsstat
self.time = time
end
# helper method to return %age of disc space free
#
def percent_free
fsstat.blocks_available * 100 / fsstat.blocks
end
end
# A simple round-robin list to store a short history of a given mount
# point's disk space history.
#
class DiskFreeHistory
attr_reader :mountpoint, :history_file
MINIMUM_INTERVAL = 5 * 60 # don't take readings more than 5 mins apart
MAXIMUM_AGE = 7 * 24 * 60 * 60 # delete readings after a week
# Initialize a new list storing the disc space history for the given
# mount point.
#
def initialize(mountpoint, history_file = nil)
history_file = "#{mountpoint}/.disk_free_history" unless
history_file
@history_file = history_file
@mountpoint = mountpoint
load!
end
# Take a new reading
#
def new_reading!
reading = DiskFreeReading.new(Sys::Filesystem.stat(@mountpoint))
# Don't record a new reading if it's exactly the same as last time,
# and less than the minimum interval.
#
return nil if @list.last &&
@list.last.fsstat.blocks_available == reading.fsstat.blocks_available &&
Time.now - @list.last.time < MINIMUM_INTERVAL
@list << reading
save!
end
def list
load! unless @list
@list
end
def gradient(last_n_seconds, &value_from_reading)
value_from_reading ||= proc { |r| r.fsstat.blocks_available }
earliest = Time.now - last_n_seconds
total = 0
readings = 0
later_reading = nil
list.reverse.each do |reading|
if later_reading
difference =
value_from_reading.call(reading) -
value_from_reading.call(later_reading)
total += difference
end
readings += 1
break if reading.time < earliest
later_reading = reading
end
return 0 if readings == 0
total / readings
end
protected
def load!
File.open(@history_file) do |fh|
@list = Marshal.restore(fh.read(1_000_000))
end
rescue Errno::ENOENT, TypeError => err
@list = []
new_reading!
end
def save!
list.shift while Time.now - list.first.time > MAXIMUM_AGE
tmp = "#{@history_file}.#{$PROCESS_ID}.#{rand(9_999_999_999)}"
begin
File.open(tmp, 'w') do |fh|
fh.write(Marshal.dump(list))
File.rename(tmp, @history_file)
end
ensure
File.unlink(tmp) if File.exist?(tmp)
end
end
end
end
|