summaryrefslogtreecommitdiffstats
path: root/pym/cache/metadata_overlay.py
blob: b12740bdb16de52b3638e11aa26e7c8f0952ecad (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
# 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, db_rw=db_rw, db_ro=db_ro,
		**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
				return
		except KeyError:
			pass
		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_"]