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
95
96
97
98
99
100
101
102
103
104
105
|
# 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
from cache import template
from cache.cache_errors import CacheCorruption
from cache.flat_hash import database as db_rw
from cache.metadata import database as db_ro
class database(template.database):
serialize_eclasses = False
def __init__(self, location, label, auxdbkeys, db_rw=db_rw, db_ro=db_ro,
*args, **config):
super_config = config.copy()
super_config.pop("gid", None)
super(database, self).__init__(location, label, auxdbkeys,
*args, **super_config)
self.db_rw = db_rw(location, label, auxdbkeys, **config)
self.commit = self.db_rw.commit
self.autocommits = self.db_rw.autocommits
if isinstance(db_ro, type):
ro_config = config.copy()
ro_config["readonly"] = True
self.db_ro = db_ro(label, "metadata/cache", auxdbkeys, **ro_config)
else:
self.db_ro = db_ro
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
except CacheCorruption:
del self.db_rw[cpv]
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):
value_ro = self.db_ro.get(name, None)
if value_ro is not None and \
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
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 __contains__(self, cpv):
try:
self[cpv] # validates whiteout when necessary
except KeyError:
return False
return True
def __iter__(self):
s = set()
for cpv in self.db_rw:
if cpv in self: # 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:
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_"]
|