1 |
commit: f36b9fa38b5268c2a5579db62acec026625f84a9 |
2 |
Author: David James <davidjames <AT> chromium <DOT> org> |
3 |
AuthorDate: Thu May 5 21:08:27 2011 +0000 |
4 |
Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> |
5 |
CommitDate: Sat May 7 01:52:39 2011 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=f36b9fa3 |
7 |
|
8 |
Cleanup preserved lib locking in portage. |
9 |
|
10 |
This change makes preserved lib modification atomic, and |
11 |
prepares us for narrowing the scope of the merge lock. |
12 |
|
13 |
BUG=chromium-os:14983 |
14 |
TEST=Ran test suite and some example emerges. |
15 |
|
16 |
Change-Id: I39abb6a5ec72be3274e508ef807ac1d9e69db1a8 |
17 |
|
18 |
Review URL: http://gerrit.chromium.org/gerrit/417 |
19 |
|
20 |
--- |
21 |
pym/_emerge/actions.py | 7 - |
22 |
pym/portage/dbapi/vartree.py | 199 ++++++++++---------- |
23 |
.../util/_dyn_libs/PreservedLibsRegistry.py | 32 ++-- |
24 |
3 files changed, 114 insertions(+), 124 deletions(-) |
25 |
|
26 |
diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py |
27 |
index 6379b36..29ecb38 100644 |
28 |
--- a/pym/_emerge/actions.py |
29 |
+++ b/pym/_emerge/actions.py |
30 |
@@ -448,13 +448,6 @@ def action_build(settings, trees, mtimedb, |
31 |
portage.writemsg_stdout(colorize("WARN", "WARNING:") |
32 |
+ " AUTOCLEAN is disabled. This can cause serious" |
33 |
+ " problems due to overlapping packages.\n") |
34 |
- plib_registry = \ |
35 |
- trees[settings["ROOT"]]["vartree"].dbapi._plib_registry |
36 |
- if plib_registry is None: |
37 |
- # preserve-libs is entirely disabled |
38 |
- pass |
39 |
- else: |
40 |
- plib_registry.pruneNonExisting() |
41 |
|
42 |
return retval |
43 |
|
44 |
|
45 |
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py |
46 |
index 08263d6..4170d3d 100644 |
47 |
--- a/pym/portage/dbapi/vartree.py |
48 |
+++ b/pym/portage/dbapi/vartree.py |
49 |
@@ -148,13 +148,9 @@ class vardbapi(dbapi): |
50 |
|
51 |
self._plib_registry = None |
52 |
if _ENABLE_PRESERVE_LIBS: |
53 |
- try: |
54 |
- self._plib_registry = PreservedLibsRegistry(self.root, |
55 |
- os.path.join(self._eroot, PRIVATE_PATH, |
56 |
- "preserved_libs_registry")) |
57 |
- except PermissionDenied: |
58 |
- # apparently this user isn't allowed to access PRIVATE_PATH |
59 |
- pass |
60 |
+ self._plib_registry = PreservedLibsRegistry(self.root, |
61 |
+ os.path.join(self._eroot, PRIVATE_PATH, |
62 |
+ "preserved_libs_registry")) |
63 |
|
64 |
self._linkmap = None |
65 |
if _ENABLE_DYN_LINK_MAP: |
66 |
@@ -1437,8 +1433,50 @@ class dblink(object): |
67 |
self.contentscache = pkgfiles |
68 |
return pkgfiles |
69 |
|
70 |
+ def _prune_plib_registry(self, unmerge=False, others_in_slot=[], |
71 |
+ needed=None): |
72 |
+ # remove preserved libraries that don't have any consumers left |
73 |
+ plib_registry = self.vartree.dbapi._plib_registry |
74 |
+ if plib_registry: |
75 |
+ plib_registry.lock() |
76 |
+ try: |
77 |
+ plib_registry.load() |
78 |
+ |
79 |
+ if unmerge: |
80 |
+ # self.mycpv is about to be unmerged, so we shouldn't pay |
81 |
+ # attention to its needs in the linkmap. |
82 |
+ exclude_pkgs = (self.mycpv,) |
83 |
+ else: |
84 |
+ exclude_pkgs = None |
85 |
+ |
86 |
+ self._linkmap_rebuild(exclude_pkgs=exclude_pkgs, |
87 |
+ include_file=needed) |
88 |
+ |
89 |
+ cpv_lib_map = self._find_unused_preserved_libs() |
90 |
+ if cpv_lib_map: |
91 |
+ self._remove_preserved_libs(cpv_lib_map) |
92 |
+ for cpv, removed in cpv_lib_map.items(): |
93 |
+ if not self.vartree.dbapi.cpv_exists(cpv): |
94 |
+ for dblnk in others_in_slot: |
95 |
+ if dblnk.mycpv == cpv: |
96 |
+ # This one just got merged so it doesn't |
97 |
+ # register with cpv_exists() yet. |
98 |
+ self.vartree.dbapi.removeFromContents( |
99 |
+ dblnk, removed) |
100 |
+ break |
101 |
+ continue |
102 |
+ self.vartree.dbapi.removeFromContents(cpv, removed) |
103 |
+ |
104 |
+ if unmerge: |
105 |
+ plib_registry.unregister(self.mycpv, self.settings["SLOT"], |
106 |
+ self.vartree.dbapi.cpv_counter(self.mycpv)) |
107 |
+ |
108 |
+ plib_registry.store() |
109 |
+ finally: |
110 |
+ plib_registry.unlock() |
111 |
+ |
112 |
def unmerge(self, pkgfiles=None, trimworld=None, cleanup=True, |
113 |
- ldpath_mtimes=None, others_in_slot=None): |
114 |
+ ldpath_mtimes=None, others_in_slot=None, needed=None): |
115 |
""" |
116 |
Calls prerm |
117 |
Unmerges a given package (CPV) |
118 |
@@ -1456,6 +1494,8 @@ class dblink(object): |
119 |
@type ldpath_mtimes: Dictionary |
120 |
@param others_in_slot: all dblink instances in this slot, excluding self |
121 |
@type others_in_slot: list |
122 |
+ @param needed: Filename containing libraries needed after unmerge. |
123 |
+ @type needed: String |
124 |
@rtype: Integer |
125 |
@returns: |
126 |
1. os.EX_OK if everything went well. |
127 |
@@ -1574,15 +1614,6 @@ class dblink(object): |
128 |
self._unmerge_pkgfiles(pkgfiles, others_in_slot) |
129 |
self._clear_contents_cache() |
130 |
|
131 |
- # Remove the registration of preserved libs for this pkg instance |
132 |
- plib_registry = self.vartree.dbapi._plib_registry |
133 |
- if plib_registry is None: |
134 |
- # preserve-libs is entirely disabled |
135 |
- pass |
136 |
- else: |
137 |
- plib_registry.unregister(self.mycpv, self.settings["SLOT"], |
138 |
- self.vartree.dbapi.cpv_counter(self.mycpv)) |
139 |
- |
140 |
if myebuildpath: |
141 |
ebuild_phase = "postrm" |
142 |
phase = EbuildPhase(background=background, |
143 |
@@ -1597,37 +1628,8 @@ class dblink(object): |
144 |
showMessage(_("!!! FAILED postrm: %s\n") % retval, |
145 |
level=logging.ERROR, noiselevel=-1) |
146 |
|
147 |
- # Skip this if another package in the same slot has just been |
148 |
- # merged on top of this package, since the other package has |
149 |
- # already called LinkageMap.rebuild() and passed it's NEEDED file |
150 |
- # in as an argument. |
151 |
- if not others_in_slot: |
152 |
- self._linkmap_rebuild(exclude_pkgs=(self.mycpv,)) |
153 |
- |
154 |
- # remove preserved libraries that don't have any consumers left |
155 |
- cpv_lib_map = self._find_unused_preserved_libs() |
156 |
- if cpv_lib_map: |
157 |
- self._remove_preserved_libs(cpv_lib_map) |
158 |
- for cpv, removed in cpv_lib_map.items(): |
159 |
- if not self.vartree.dbapi.cpv_exists(cpv): |
160 |
- for dblnk in others_in_slot: |
161 |
- if dblnk.mycpv == cpv: |
162 |
- # This one just got merged so it doesn't |
163 |
- # register with cpv_exists() yet. |
164 |
- self.vartree.dbapi.removeFromContents( |
165 |
- dblnk, removed) |
166 |
- break |
167 |
- continue |
168 |
- self.vartree.dbapi.removeFromContents(cpv, removed) |
169 |
- else: |
170 |
- # Prune any preserved libs that may have |
171 |
- # been unmerged with this package. |
172 |
- if plib_registry is None: |
173 |
- # preserve-libs is entirely disabled |
174 |
- pass |
175 |
- else: |
176 |
- plib_registry.pruneNonExisting() |
177 |
- |
178 |
+ self._prune_plib_registry(unmerge=True, |
179 |
+ others_in_slot=others_in_slot, needed=needed) |
180 |
finally: |
181 |
self.vartree.dbapi._bump_mtime(self.mycpv) |
182 |
if builddir_lock: |
183 |
@@ -3268,15 +3270,22 @@ class dblink(object): |
184 |
self._clear_contents_cache() |
185 |
|
186 |
linkmap = self.vartree.dbapi._linkmap |
187 |
- if linkmap is None: |
188 |
- # preserve-libs is entirely disabled |
189 |
+ plib_registry = self.vartree.dbapi._plib_registry |
190 |
+ include_file = None |
191 |
+ if linkmap is None or plib_registry is None: |
192 |
preserve_paths = None |
193 |
else: |
194 |
- self._linkmap_rebuild(include_file=os.path.join(inforoot, |
195 |
- linkmap._needed_aux_key)) |
196 |
+ plib_registry.lock() |
197 |
+ try: |
198 |
+ plib_registry.load() |
199 |
+ needed = os.path.join(inforoot, linkmap._needed_aux_key) |
200 |
+ self._linkmap_rebuild(include_file=needed) |
201 |
+ |
202 |
+ # Preserve old libs if they are still in use |
203 |
+ preserve_paths = self._find_libs_to_preserve() |
204 |
+ finally: |
205 |
+ plib_registry.unlock() |
206 |
|
207 |
- # Preserve old libs if they are still in use |
208 |
- preserve_paths = self._find_libs_to_preserve() |
209 |
if preserve_paths: |
210 |
self._add_preserve_libs_to_contents(preserve_paths) |
211 |
|
212 |
@@ -3312,7 +3321,7 @@ class dblink(object): |
213 |
dblnk.settings["REPLACED_BY_VERSION"] = portage.versions.cpv_getversion(self.mycpv) |
214 |
dblnk.settings.backup_changes("REPLACED_BY_VERSION") |
215 |
unmerge_rval = dblnk.unmerge(ldpath_mtimes=prev_mtimes, |
216 |
- others_in_slot=others_in_slot) |
217 |
+ others_in_slot=others_in_slot, needed=needed) |
218 |
dblnk.settings.pop("REPLACED_BY_VERSION", None) |
219 |
|
220 |
if unmerge_rval == os.EX_OK: |
221 |
@@ -3335,12 +3344,6 @@ class dblink(object): |
222 |
self.delete() |
223 |
_movefile(self.dbtmpdir, self.dbpkgdir, mysettings=self.settings) |
224 |
|
225 |
- # keep track of the libs we preserved |
226 |
- if self.vartree.dbapi._plib_registry is not None and \ |
227 |
- preserve_paths: |
228 |
- self.vartree.dbapi._plib_registry.register(self.mycpv, |
229 |
- slot, counter, sorted(preserve_paths)) |
230 |
- |
231 |
# Check for file collisions with blocking packages |
232 |
# and remove any colliding files from their CONTENTS |
233 |
# since they now belong to this package. |
234 |
@@ -3351,27 +3354,37 @@ class dblink(object): |
235 |
self.vartree.dbapi.removeFromContents(blocker, iter(contents), |
236 |
relative_paths=False) |
237 |
|
238 |
- # Unregister any preserved libs that this package has overwritten |
239 |
- # and update the contents of the packages that owned them. |
240 |
plib_registry = self.vartree.dbapi._plib_registry |
241 |
- if plib_registry is None: |
242 |
- # preserve-libs is entirely disabled |
243 |
- pass |
244 |
- else: |
245 |
- plib_dict = plib_registry.getPreservedLibs() |
246 |
- for cpv, paths in plib_collisions.items(): |
247 |
- if cpv not in plib_dict: |
248 |
- continue |
249 |
- if cpv == self.mycpv: |
250 |
- continue |
251 |
- try: |
252 |
- slot, counter = self.vartree.dbapi.aux_get( |
253 |
- cpv, ["SLOT", "COUNTER"]) |
254 |
- except KeyError: |
255 |
- continue |
256 |
- remaining = [f for f in plib_dict[cpv] if f not in paths] |
257 |
- plib_registry.register(cpv, slot, counter, remaining) |
258 |
- self.vartree.dbapi.removeFromContents(cpv, paths) |
259 |
+ if plib_registry: |
260 |
+ plib_registry.lock() |
261 |
+ try: |
262 |
+ plib_registry.load() |
263 |
+ |
264 |
+ if preserve_paths: |
265 |
+ # keep track of the libs we preserved |
266 |
+ plib_registry.register(self.mycpv, slot, counter, |
267 |
+ sorted(preserve_paths)) |
268 |
+ |
269 |
+ # Unregister any preserved libs that this package has overwritten |
270 |
+ # and update the contents of the packages that owned them. |
271 |
+ plib_dict = plib_registry.getPreservedLibs() |
272 |
+ for cpv, paths in plib_collisions.items(): |
273 |
+ if cpv not in plib_dict: |
274 |
+ continue |
275 |
+ if cpv == self.mycpv: |
276 |
+ continue |
277 |
+ try: |
278 |
+ slot, counter = self.vartree.dbapi.aux_get( |
279 |
+ cpv, ["SLOT", "COUNTER"]) |
280 |
+ except KeyError: |
281 |
+ continue |
282 |
+ remaining = [f for f in plib_dict[cpv] if f not in paths] |
283 |
+ plib_registry.register(cpv, slot, counter, remaining) |
284 |
+ self.vartree.dbapi.removeFromContents(cpv, paths) |
285 |
+ |
286 |
+ plib_registry.store() |
287 |
+ finally: |
288 |
+ plib_registry.unlock() |
289 |
|
290 |
self.vartree.dbapi._add(self) |
291 |
contents = self.getcontents() |
292 |
@@ -3410,14 +3423,7 @@ class dblink(object): |
293 |
|
294 |
# For gcc upgrades, preserved libs have to be removed after the |
295 |
# the library path has been updated. |
296 |
- self._linkmap_rebuild() |
297 |
- cpv_lib_map = self._find_unused_preserved_libs() |
298 |
- if cpv_lib_map: |
299 |
- self._remove_preserved_libs(cpv_lib_map) |
300 |
- for cpv, removed in cpv_lib_map.items(): |
301 |
- if not self.vartree.dbapi.cpv_exists(cpv): |
302 |
- continue |
303 |
- self.vartree.dbapi.removeFromContents(cpv, removed) |
304 |
+ self._prune_plib_registry() |
305 |
|
306 |
return os.EX_OK |
307 |
|
308 |
@@ -3839,14 +3845,6 @@ class dblink(object): |
309 |
self.lockdb() |
310 |
self.vartree.dbapi._bump_mtime(self.mycpv) |
311 |
try: |
312 |
- plib_registry = self.vartree.dbapi._plib_registry |
313 |
- if plib_registry is None: |
314 |
- # preserve-libs is entirely disabled |
315 |
- pass |
316 |
- else: |
317 |
- plib_registry.load() |
318 |
- plib_registry.pruneNonExisting() |
319 |
- |
320 |
retval = self.treewalk(mergeroot, myroot, inforoot, myebuild, |
321 |
cleanup=cleanup, mydbapi=mydbapi, prev_mtimes=prev_mtimes) |
322 |
|
323 |
@@ -4001,13 +3999,6 @@ def unmerge(cat, pkg, myroot=None, settings=None, |
324 |
try: |
325 |
mylink.lockdb() |
326 |
if mylink.exists(): |
327 |
- plib_registry = vartree.dbapi._plib_registry |
328 |
- if plib_registry is None: |
329 |
- # preserve-libs is entirely disabled |
330 |
- pass |
331 |
- else: |
332 |
- plib_registry.load() |
333 |
- plib_registry.pruneNonExisting() |
334 |
retval = mylink.unmerge(ldpath_mtimes=ldpath_mtimes) |
335 |
if retval == os.EX_OK: |
336 |
mylink.delete() |
337 |
|
338 |
diff --git a/pym/portage/util/_dyn_libs/PreservedLibsRegistry.py b/pym/portage/util/_dyn_libs/PreservedLibsRegistry.py |
339 |
index 0d0b57d..f3cbb33 100644 |
340 |
--- a/pym/portage/util/_dyn_libs/PreservedLibsRegistry.py |
341 |
+++ b/pym/portage/util/_dyn_libs/PreservedLibsRegistry.py |
342 |
@@ -18,23 +18,29 @@ from portage.localization import _ |
343 |
from portage.util import atomic_ofstream |
344 |
from portage.util import writemsg_level |
345 |
from portage.versions import cpv_getkey |
346 |
+from portage.locks import lockfile, unlockfile |
347 |
|
348 |
class PreservedLibsRegistry(object): |
349 |
""" This class handles the tracking of preserved library objects """ |
350 |
- def __init__(self, root, filename, autocommit=True): |
351 |
+ def __init__(self, root, filename): |
352 |
""" |
353 |
@param root: root used to check existence of paths in pruneNonExisting |
354 |
@type root: String |
355 |
@param filename: absolute path for saving the preserved libs records |
356 |
@type filename: String |
357 |
- @param autocommit: determines if the file is written after every update |
358 |
- @type autocommit: Boolean |
359 |
""" |
360 |
self._root = root |
361 |
self._filename = filename |
362 |
- self._autocommit = autocommit |
363 |
- self.load() |
364 |
- self.pruneNonExisting() |
365 |
+ self._data = None |
366 |
+ self._lock = None |
367 |
+ |
368 |
+ def lock(self): |
369 |
+ """Grab an exclusive lock on the preserved libs registry.""" |
370 |
+ self._lock = lockfile(self._filename) |
371 |
+ |
372 |
+ def unlock(self): |
373 |
+ """Release our exclusive lock on the preserved libs registry.""" |
374 |
+ unlockfile(self._lock) |
375 |
|
376 |
def load(self): |
377 |
""" Reload the registry data from file """ |
378 |
@@ -56,10 +62,10 @@ class PreservedLibsRegistry(object): |
379 |
if self._data is None: |
380 |
self._data = {} |
381 |
self._data_orig = self._data.copy() |
382 |
+ self.pruneNonExisting() |
383 |
+ |
384 |
def store(self): |
385 |
- """ Store the registry data to file. No need to call this if autocommit |
386 |
- was enabled. |
387 |
- """ |
388 |
+ """ Store the registry data to file """ |
389 |
if os.environ.get("SANDBOX_ON") == "1" or \ |
390 |
self._data == self._data_orig: |
391 |
return |
392 |
@@ -94,8 +100,6 @@ class PreservedLibsRegistry(object): |
393 |
del self._data[cps] |
394 |
elif len(paths) > 0: |
395 |
self._data[cps] = (cpv, counter, paths) |
396 |
- if self._autocommit: |
397 |
- self.store() |
398 |
|
399 |
def unregister(self, cpv, slot, counter): |
400 |
""" Remove a previous registration of preserved objects for the given package. |
401 |
@@ -119,11 +123,11 @@ class PreservedLibsRegistry(object): |
402 |
self._data[cps] = (cpv, counter, paths) |
403 |
else: |
404 |
del self._data[cps] |
405 |
- if self._autocommit: |
406 |
- self.store() |
407 |
|
408 |
def hasEntries(self): |
409 |
""" Check if this registry contains any records. """ |
410 |
+ if self._data is None: |
411 |
+ self.load() |
412 |
return len(self._data) > 0 |
413 |
|
414 |
def getPreservedLibs(self): |
415 |
@@ -131,6 +135,8 @@ class PreservedLibsRegistry(object): |
416 |
@returns mapping of package instances to preserved objects |
417 |
@rtype Dict cpv->list-of-paths |
418 |
""" |
419 |
+ if self._data is None: |
420 |
+ self.load() |
421 |
rValue = {} |
422 |
for cps in self._data: |
423 |
rValue[self._data[cps][0]] = self._data[cps][2] |