Add a new cache.metadata_overlay module that layers a writable cache over a readonly...
authorZac Medico <zmedico@gentoo.org>
Sun, 26 Feb 2006 13:10:43 +0000 (13:10 -0000)
committerZac Medico <zmedico@gentoo.org>
Sun, 26 Feb 2006 13:10:43 +0000 (13:10 -0000)
svn path=/main/trunk/; revision=2792

pym/cache/metadata_overlay.py [new file with mode: 0644]

diff --git a/pym/cache/metadata_overlay.py b/pym/cache/metadata_overlay.py
new file mode 100644 (file)
index 0000000..557855a
--- /dev/null
@@ -0,0 +1,91 @@
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+import time
+if not hasattr(__builtins__, "set"):
+       from sets import Set as set
+import template
+from flat_hash import database as db_rw
+from metadata import database as db_ro
+
+class database(template.database):
+
+       autocommits = True
+       serialize_eclasses = False
+
+       def __init__(self, location, label, auxdbkeys, **config):
+               super(database, self).__init__(location, label, auxdbkeys)
+               self.db_rw = db_rw(location, label, auxdbkeys, **config)
+               self.db_ro = db_ro(label,"metadata/cache",auxdbkeys)
+
+       def __getitem__(self, cpv):
+               """funnel whiteout validation through here, since value needs to be fetched"""
+               try:
+                       value = self.db_rw[cpv]
+               except KeyError:
+                       return self.db_ro[cpv] # raises a KeyError when necessary
+               if self._is_whiteout(value):
+                       if self._is_whiteout_valid(cpv, value):
+                               raise KeyError(cpv)
+                       else:
+                               del self.db_rw[cpv]
+                               return self.db_ro[cpv] # raises a KeyError when necessary
+               else:
+                       return value
+
+       def _setitem(self, name, values):
+               try:
+                       value_ro = self.db_ro[name]
+                       if self._are_values_identical(value_ro,values):
+                               # we have matching values in the underlying db_ro
+                               # so it is unnecessary to store data in db_rw
+                               try:
+                                       del self.db_rw[name] # delete unwanted whiteout when necessary
+                               except KeyError:
+                                       pass
+               except KeyError:
+                       self.db_rw[name] = values
+
+       def _delitem(self, cpv):
+               value = self[cpv] # validates whiteout and/or raises a KeyError when necessary
+               if self.db_ro.has_key(cpv):
+                       self.db_rw[cpv] = self._create_whiteout(value)
+               else:
+                       del self.db_rw[cpv]
+
+       def has_key(self, cpv):
+               try:
+                       self[cpv] # validates whiteout when necessary
+               except KeyError:
+                       return False
+               return True
+
+       def iterkeys(self):
+               s = set()
+               for cpv in self.db_rw.iterkeys():
+                       if self.has_key(cpv): # validates whiteout when necessary
+                               yield cpv
+                       # set includes whiteouts so they won't be yielded later
+                       s.add(cpv)
+               for cpv in self.db_ro.iterkeys():
+                       if cpv not in s:
+                               yield cpv
+
+       def _is_whiteout(self, value):
+               return value["EAPI"] == "whiteout"
+
+       def _create_whiteout(self, value):
+               return {"EAPI":"whiteout","_eclasses_":value["_eclasses_"],"_mtime_":value["_mtime_"]}
+
+       def _is_whiteout_valid(self, name, value_rw):
+               try:
+                       value_ro = self.db_ro[name]
+                       return self._are_values_identical(value_rw,value_ro)
+               except KeyError:
+                       return False
+
+       def _are_values_identical(self, value1, value2):
+               if long(value1["_mtime_"]) != long(value2["_mtime_"]):
+                       return False
+               return value1["_eclasses_"] == value2["_eclasses_"]