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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
# Copyright: 2005 Gentoo Foundation
# Author(s): Brian Harring (ferringb@gentoo.org)
# License: GPL2
# $Id: template.py 1911 2005-08-25 03:44:21Z ferringb $
import cache_errors
from mappings import ProtectedDict
class database(object):
# this is for metadata/cache transfer.
# basically flags the cache needs be updated when transfered cache to cache.
# leave this.
complete_eclass_entries_ = True
autocommits = False
cleanse_keys = False
serialize_eclasses = True
def __init__(self, location, label, auxdbkeys, readonly=False):
""" initialize the derived class; specifically, store label/keys"""
self._known_keys = auxdbkeys
self.location = location
self.label = label
self.readonly = readonly
self.sync_rate = 0
self.updates = 0
def __getitem__(self, cpv):
"""set a cpv to values
This shouldn't be overriden in derived classes since it handles the __eclasses__ conversion.
that said, if the class handles it, they can override it."""
if self.updates > self.sync_rate:
self.commit()
self.updates = 0
d=self._getitem(cpv)
if self.serialize_eclasses and "_eclasses_" in d:
d["_eclasses_"] = reconstruct_eclasses(cpv, d["_eclasses_"])
return d
def _getitem(self, cpv):
"""get cpv's values.
override this in derived classess"""
raise NotImplementedError
def __setitem__(self, cpv, values):
"""set a cpv to values
This shouldn't be overriden in derived classes since it handles the readonly checks"""
if self.readonly:
raise cache_errors.ReadOnlyRestriction()
if self.cleanse_keys:
d=ProtectedDict(values)
for k in d.keys():
if d[k] == '':
del d[k]
if self.serialize_eclasses and "_eclasses_" in values:
d["_eclasses_"] = serialize_eclasses(d["_eclasses_"])
elif self.serialize_eclasses and "_eclasses_" in values:
d = ProtectedDict(values)
d["_eclasses_"] = serialize_eclasses(d["_eclasses_"])
else:
d = values
self._setitem(cpv, d)
if not self.autocommits:
self.updates += 1
if self.updates > self.sync_rate:
self.commit()
self.updates = 0
def _setitem(self, name, values):
"""__setitem__ calls this after readonly checks. override it in derived classes
note _eclassees_ key *must* be handled"""
raise NotImplementedError
def __delitem__(self, cpv):
"""delete a key from the cache.
This shouldn't be overriden in derived classes since it handles the readonly checks"""
if self.readonly:
raise cache_errors.ReadOnlyRestriction()
if not self.autocommits:
self.updates += 1
self._delitem(cpv)
if self.updates > self.sync_rate:
self.commit()
self.updates = 0
def _delitem(self,cpv):
"""__delitem__ calls this after readonly checks. override it in derived classes"""
raise NotImplementedError
def has_key(self, cpv):
raise NotImplementedError
def keys(self):
return tuple(self.iterkeys())
def iterkeys(self):
raise NotImplementedError
def iteritems(self):
for x in self.iterkeys():
yield (x, self[x])
def items(self):
return list(self.iteritems())
def sync(self, rate=0):
self.sync_rate = rate
if(rate == 0):
self.commit()
def commit(self):
if not self.autocommits:
raise NotImplementedError
def __contains__(self, cpv):
return self.has_key(cpv)
def get_matches(self, match_dict):
"""generic function for walking the entire cache db, matching restrictions to
filter what cpv's are returned. Derived classes should override this if they
can implement a faster method then pulling each cpv:values, and checking it.
For example, RDBMS derived classes should push the matching logic down to the
actual RDBM."""
import re
restricts = {}
for key,match in match_dict.iteritems():
# XXX this sucks.
try:
if isinstance(match, str):
restricts[key] = re.compile(match).match
else:
restricts[key] = re.compile(match[0],match[1]).match
except re.error, e:
raise InvalidRestriction(key, match, e)
if key not in self.__known_keys:
raise InvalidRestriction(key, match, "Key isn't valid")
for cpv in self.keys():
cont = True
vals = self[cpv]
for key, match in restricts.iteritems():
if not match(vals[key]):
cont = False
break
if cont:
yield cpv
def serialize_eclasses(eclass_dict):
"""takes a dict, returns a string representing said dict"""
return "\t".join(["%s\t%s\t%s" % (k, v[0], str(v[1])) for k,v in eclass_dict.items()])
def reconstruct_eclasses(cpv, eclass_string):
"""returns a dict when handed a string generated by serialize_eclasses"""
eclasses = eclass_string.rstrip().lstrip().split("\t")
if eclasses == [""]:
# occasionally this occurs in the fs backends. they suck.
return {}
if len(eclasses) % 3 != 0:
raise cache_errors.CacheCorruption(cpv, "_eclasses_ was of invalid len %i" % len(eclasses))
d={}
for x in range(0, len(eclasses), 3):
d[eclasses[x]] = (eclasses[x + 1], long(eclasses[x + 2]))
del eclasses
return d
|