mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-05-01 08:20:51 +00:00
diskwatcher: record total-space (the size of the disk as reported by df) in the db, report it to HTTP clients. This will involve a 50-item-per-second upgrade process when it is first used on old data
This commit is contained in:
parent
d6a67cd566
commit
0a819e2912
@ -1,14 +1,32 @@
|
|||||||
|
|
||||||
# put this definition in a separate file, because axiom uses the
|
|
||||||
# fully-qualified classname as a database table name, so __builtin__ is kinda
|
|
||||||
# ugly.
|
|
||||||
|
|
||||||
from axiom.item import Item
|
from axiom.item import Item
|
||||||
from axiom.attributes import text, integer, timestamp
|
from axiom.attributes import text, integer, timestamp
|
||||||
|
|
||||||
|
|
||||||
class Sample(Item):
|
class Sample(Item):
|
||||||
|
# we didn't originally set typeName, so it was generated from the
|
||||||
|
# fully-qualified classname ("diskwatcher.Sample"), then Axiom
|
||||||
|
# automatically lowercases and un-dot-ifies it to get
|
||||||
|
# "diskwatcher_sample". Now we explicitly provide a name.
|
||||||
|
typeName = "diskwatcher_sample"
|
||||||
|
|
||||||
|
# version 2 added the 'total' field
|
||||||
|
schemaVersion = 2
|
||||||
|
|
||||||
url = text(indexed=True)
|
url = text(indexed=True)
|
||||||
when = timestamp(indexed=True)
|
when = timestamp(indexed=True)
|
||||||
|
total = integer()
|
||||||
used = integer()
|
used = integer()
|
||||||
avail = integer()
|
avail = integer()
|
||||||
|
|
||||||
|
def upgradeSample1to2(old):
|
||||||
|
total = 0
|
||||||
|
return old.upgradeVersion("diskwatcher_sample", 1, 2,
|
||||||
|
url=old.url,
|
||||||
|
when=old.when,
|
||||||
|
total=0,
|
||||||
|
used=old.used,
|
||||||
|
avail=old.avail)
|
||||||
|
|
||||||
|
from axiom.upgrade import registerUpgrader
|
||||||
|
registerUpgrader(upgradeSample1to2, "diskwatcher_sample", 1, 2)
|
||||||
|
@ -75,9 +75,14 @@ class DiskWatcher(service.MultiService, resource.Resource):
|
|||||||
service.MultiService.__init__(self)
|
service.MultiService.__init__(self)
|
||||||
resource.Resource.__init__(self)
|
resource.Resource.__init__(self)
|
||||||
self.store = Store("history.axiom")
|
self.store = Store("history.axiom")
|
||||||
|
self.store.whenFullyUpgraded().addCallback(self._upgrade_complete)
|
||||||
|
service.IService(self.store).setServiceParent(self) # let upgrader run
|
||||||
ts = internet.TimerService(self.POLL_INTERVAL, self.poll)
|
ts = internet.TimerService(self.POLL_INTERVAL, self.poll)
|
||||||
ts.setServiceParent(self)
|
ts.setServiceParent(self)
|
||||||
|
|
||||||
|
def _upgrade_complete(self, ignored):
|
||||||
|
print "Axiom store upgrade complete"
|
||||||
|
|
||||||
def startService(self):
|
def startService(self):
|
||||||
service.MultiService.startService(self)
|
service.MultiService.startService(self)
|
||||||
|
|
||||||
@ -152,7 +157,7 @@ class DiskWatcher(service.MultiService, resource.Resource):
|
|||||||
print "%s : total=%s, used=%s, avail=%s" % (url,
|
print "%s : total=%s, used=%s, avail=%s" % (url,
|
||||||
total, used, avail)
|
total, used, avail)
|
||||||
Sample(store=self.store,
|
Sample(store=self.store,
|
||||||
url=unicode(url), when=when, used=used, avail=avail)
|
url=unicode(url), when=when, total=total, used=used, avail=avail)
|
||||||
|
|
||||||
def calculate_growth_timeleft(self):
|
def calculate_growth_timeleft(self):
|
||||||
timespans = []
|
timespans = []
|
||||||
@ -170,6 +175,23 @@ class DiskWatcher(service.MultiService, resource.Resource):
|
|||||||
timespans.append( (name, timespan, growth, timeleft) )
|
timespans.append( (name, timespan, growth, timeleft) )
|
||||||
return timespans
|
return timespans
|
||||||
|
|
||||||
|
def find_total_space(self):
|
||||||
|
# this returns the sum of disk-avail stats for all servers that 1)
|
||||||
|
# are listed in urls.txt and 2) have responded recently.
|
||||||
|
now = extime.Time()
|
||||||
|
recent = now - timedelta(seconds=2*self.POLL_INTERVAL)
|
||||||
|
total_space = 0
|
||||||
|
for url in self.get_urls():
|
||||||
|
url = unicode(url)
|
||||||
|
latest = list(self.store.query(Sample,
|
||||||
|
AND(Sample.url == url,
|
||||||
|
Sample.when > recent),
|
||||||
|
sort=Sample.when.descending,
|
||||||
|
limit=1))
|
||||||
|
if latest:
|
||||||
|
total_space += latest[0].total
|
||||||
|
return total_space
|
||||||
|
|
||||||
def find_total_available_space(self):
|
def find_total_available_space(self):
|
||||||
# this returns the sum of disk-avail stats for all servers that 1)
|
# this returns the sum of disk-avail stats for all servers that 1)
|
||||||
# are listed in urls.txt and 2) have responded recently.
|
# are listed in urls.txt and 2) have responded recently.
|
||||||
@ -283,6 +305,37 @@ class DiskWatcher(service.MultiService, resource.Resource):
|
|||||||
return _plural(s/MONTH, "month")
|
return _plural(s/MONTH, "month")
|
||||||
return _plural(s/YEAR, "year")
|
return _plural(s/YEAR, "year")
|
||||||
|
|
||||||
|
def abbreviate_space2(self, s, SI=True):
|
||||||
|
def _plural(count, unit):
|
||||||
|
count = int(count)
|
||||||
|
return "%d %s" % (count, unit)
|
||||||
|
if s is None:
|
||||||
|
return "unknown"
|
||||||
|
if SI:
|
||||||
|
U = 1000.0
|
||||||
|
isuffix = "B"
|
||||||
|
else:
|
||||||
|
U = 1024.0
|
||||||
|
isuffix = "iB"
|
||||||
|
def r(count, suffix):
|
||||||
|
return "%.2f %s%s" % (count, suffix, isuffix)
|
||||||
|
|
||||||
|
if s < 1024: # 1000-1023 get emitted as bytes, even in SI mode
|
||||||
|
return r(s, "")
|
||||||
|
if s < U*U:
|
||||||
|
return r(s/U, "k")
|
||||||
|
if s < U*U*U:
|
||||||
|
return r(s/(U*U), "M")
|
||||||
|
if s < U*U*U*U:
|
||||||
|
return r(s/(U*U*U), "G")
|
||||||
|
if s < U*U*U*U*U:
|
||||||
|
return r(s/(U*U*U*U), "T")
|
||||||
|
return r(s/(U*U*U*U*U), "P")
|
||||||
|
|
||||||
|
def abbreviate_space(self, s):
|
||||||
|
return "(%s, %s)" % (self.abbreviate_space2(s, True),
|
||||||
|
self.abbreviate_space2(s, False))
|
||||||
|
|
||||||
def render(self, req):
|
def render(self, req):
|
||||||
t = req.args.get("t", ["html"])[0]
|
t = req.args.get("t", ["html"])[0]
|
||||||
ctype = "text/plain"
|
ctype = "text/plain"
|
||||||
@ -290,12 +343,18 @@ class DiskWatcher(service.MultiService, resource.Resource):
|
|||||||
if t == "html":
|
if t == "html":
|
||||||
data = ""
|
data = ""
|
||||||
for (name, timespan, growth, timeleft) in self.calculate_growth_timeleft():
|
for (name, timespan, growth, timeleft) in self.calculate_growth_timeleft():
|
||||||
data += "%f bytes per second, %s remaining (over %s)\n" % \
|
data += "%f bytes per second (%sps), %s remaining (over %s)\n" % \
|
||||||
(growth, self.abbreviate_time(timeleft), name)
|
(growth, self.abbreviate_space2(growth, True),
|
||||||
|
self.abbreviate_time(timeleft), name)
|
||||||
used = self.find_total_used_space()
|
used = self.find_total_used_space()
|
||||||
data += "total used: %d bytes\n" % used
|
data += "total used: %d bytes %s\n" % (used,
|
||||||
|
self.abbreviate_space(used))
|
||||||
|
total = self.find_total_space()
|
||||||
|
data += "total space: %d bytes %s\n" % (total,
|
||||||
|
self.abbreviate_space(total))
|
||||||
elif t == "json":
|
elif t == "json":
|
||||||
current = {"rates": self.calculate_growth_timeleft(),
|
current = {"rates": self.calculate_growth_timeleft(),
|
||||||
|
"total": self.find_total_space(),
|
||||||
"used": self.find_total_used_space(),
|
"used": self.find_total_used_space(),
|
||||||
"available": self.find_total_available_space(),
|
"available": self.find_total_available_space(),
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user