-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Brian Harring wrote:
> You need white outs here (lifting a unionfs term); this won't actually 
> change state in any way if you're trying to delete a bad entry from 
> the underlying metadata cache.

I've implemented whiteouts so that items can now be deleted properly.  The 
whiteouts themselves are stored inside the existing writable database 
(self.db_rw) in order to avoid the need for an additional storage area (similar 
to unionfs whiteouts which are implemented as hidden files).

The whiteouts (if they exist) are validated on access and removed if necessary. 
 A whiteout is considered invalid if it's _mtime_ and _eclasses_ are not 
exactly equal to underlying database entry that it erases (or the underlying 
database entry no longer exists).  This should cause whiteouts to be 
automatically invalidated whenever the underlying cache changes.

> Aside from that, the label trick is icky. ;)

Well yeah, but that was the only obvious way that I could see to implement the 
module within the existing framework.  I think we should modify the framework 
to allow for a more appealing alternative.

Zac
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFD3JMf/ejvha5XGaMRAitfAKDrw2C09xIzDyMZ6nVNHdIU1K1l3wCeLvIi
hD4yWTjTdRtPQyuAQQ6TtFc=
=Yr2K
-----END PGP SIGNATURE-----
# Copyright: 2006 Gentoo Foundation
# Author(s): Zac Medico ([EMAIL PROTECTED])
# License: GPL2

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):
		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]
			if long(value_rw["_mtime_"]) != long(value_ro["_mtime_"]):
				return False
			return value_rw["_eclasses_"] == value_ro["_eclasses_"]
		except KeyError:
			return False

Reply via email to