pvl.web.rrd: --cache
authorTero Marttila <terom@paivola.fi>
Sun, 20 Jan 2013 18:51:51 +0200
changeset 154 11df86fd2d67
parent 153 8930f54b59b4
child 155 9f2967ba81ef
pvl.web.rrd: --cache
bin/pvl.verkko-rrd
pvl/verkko/rrd.py
--- a/bin/pvl.verkko-rrd	Sun Jan 20 18:31:21 2013 +0200
+++ b/bin/pvl.verkko-rrd	Sun Jan 20 18:51:51 2013 +0200
@@ -33,7 +33,10 @@
     parser.add_option_group(pvl.args.parser(parser))
 
     parser.add_option('--rrd', metavar='PATH',
-        help="Path to RRD files")
+        help="Find RRD files")
+
+    parser.add_option('--cache', metavar='PATH',
+        help="Cache RRD graphs")
 
     # parse
     options, args = parser.parse_args(args)
@@ -56,7 +59,7 @@
         log.error("no --rrd given")
         return 2
 
-    rrd = pvl.verkko.rrd.RRDDatabase(options.rrd)
+    rrd = pvl.verkko.rrd.RRDDatabase(options.rrd, options.cache)
 
     # app
     application = pvl.verkko.rrd.Application(rrd)
--- a/pvl/verkko/rrd.py	Sun Jan 20 18:31:21 2013 +0200
+++ b/pvl/verkko/rrd.py	Sun Jan 20 18:51:51 2013 +0200
@@ -12,20 +12,21 @@
 import logging; log = logging.getLogger('pvl.verkko.rrd')
 
 # Model
-import os, os.path
+import os, os.path, errno
 
 class RRDDatabase (object) :
     """
         A filesystem directory containing .rrd files.
     """
 
-    def __init__ (self, path) :
+    def __init__ (self, path, cache=None) :
         if not path :
             raise ValueError("RRDDatabase: no path given")
 
-        log.info("%s", path)
+        log.info("%s: cache=%s", path, cache)
 
         self._path = path
+        self._cache = cache
 
     def path (self, node=None, *subnodes) :
         """
@@ -73,10 +74,8 @@
 
         if tree :
             node = os.path.join(tree, node)
-
-        node += '.rrd'
         
-        path = self.path(node)
+        path = self.path(node) + '.rrd'
 
         if not os.path.isfile(path) :
             raise ValueError("%: Invalid rrd: %s: %s" % (self, node, path))
@@ -110,21 +109,77 @@
         # return sorted lists
         return sorted(dirs), sorted(rrds)
     
+    def _stat (self, path) :
+        """
+            os.stat or None.
+        """
+
+        try :
+            return os.stat(path)
+
+        except OSError as ex :
+            if ex.errno == errno.ENOENT :
+                return None
+            else :
+                raise
+
+    def cache (self, source, *key) :
+        """
+            Lookup given key from cache, returning (hit, file).
+        """
+
+        # output
+        if not self._cache :
+            return None, None
+
+        # cache path
+        path = os.path.join(self._cache, *key)
+        
+        # create
+        dir = os.path.dirname(path)
+        if not os.path.isdir(dir) :
+            log.warn("makedirs %s", dir)
+            os.makedirs(dir)
+        
+        # stats's
+        src = self._stat(source)
+        dst = self._stat(path)
+
+        if not dst:
+            log.debug("%s: %s: %s: miss", self._cache, source, path)
+            return None, path
+            
+        elif dst and src.st_mtime < dst.st_mtime :
+            log.debug("%s: %s: %s: hit", self._cache, source, path)
+
+            return True, path
+
+        else :
+            log.debug("%s: %s: %s: update", self._cache, source, path)
+            return False, path
+
     def graph (self, rrd, style, interval) :
         """
             Graph given rrd using given style/interval, returning the opened png data file.
         """
         
-        title = " / ".join(rrd.split('/'))
-
-        log.debug("%s: %s: %s/%s", self, rrd, style, interval)
+        title = str(rrd) # " / ".join(rrd.split('/'))
         
-        # XXX: lookup graph style..
-        # XXX: collectd
-        # XXX: out=None -> tempfile
-        dimensions, lines, outfile = pvl.rrd.graph.collectd_ifoctets(style, interval, title, self.path(rrd), None)
+        path = self.path(rrd) + '.rrd'
 
-        log.debug("%s: %s: %s", self, rrd, outfile)
+        cached, out = self.cache(path, style, interval, rrd + '.png')
+        
+        log.debug("%s: %s: %s", self, rrd, out)
+        
+        if cached :
+            # from cache
+            outfile = open(out)
+
+        else :
+            # to cache
+            # XXX: lookup graph style..
+            # XXX: collectd
+            dimensions, lines, outfile = pvl.rrd.graph.collectd_ifoctets(style, interval, title, path, out)
 
         return outfile