1 |
Searching of installed packages is optimized to take advantage of |
2 |
vardbdbapi._aux_cache, which is backed by vdb_metadata.pickle. |
3 |
This class only implements a subset of vardbapi functionality that is |
4 |
useful for searching incrementally. For this reason, the cp_all method |
5 |
returns an ordered iterator instead of a list, so that search results |
6 |
can be displayed incrementally. |
7 |
|
8 |
X-Gentoo-Bug: 525718 |
9 |
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=525718 |
10 |
--- |
11 |
pym/portage/dbapi/IndexedVardb.py | 87 +++++++++++++++++++++++++++++++++++++++ |
12 |
pym/portage/dbapi/vartree.py | 19 +++++++-- |
13 |
2 files changed, 102 insertions(+), 4 deletions(-) |
14 |
create mode 100644 pym/portage/dbapi/IndexedVardb.py |
15 |
|
16 |
diff --git a/pym/portage/dbapi/IndexedVardb.py b/pym/portage/dbapi/IndexedVardb.py |
17 |
new file mode 100644 |
18 |
index 0000000..b2d894b |
19 |
--- /dev/null |
20 |
+++ b/pym/portage/dbapi/IndexedVardb.py |
21 |
@@ -0,0 +1,87 @@ |
22 |
+# Copyright 2014 Gentoo Foundation |
23 |
+# Distributed under the terms of the GNU General Public License v2 |
24 |
+ |
25 |
+import portage |
26 |
+from portage.dep import Atom |
27 |
+from portage.versions import _pkg_str |
28 |
+ |
29 |
+class IndexedVardb(object): |
30 |
+ """ |
31 |
+ A vardbapi interface that sacrifices validation in order to |
32 |
+ improve performance. It takes advantage of vardbdbapi._aux_cache, |
33 |
+ which is backed by vdb_metadata.pickle. Since _aux_cache is |
34 |
+ not updated for every single merge/unmerge (see |
35 |
+ _aux_cache_threshold), the list of packages is obtained directly |
36 |
+ from the real vardbapi instance. If a package is missing from |
37 |
+ _aux_cache, then its metadata is obtained using the normal |
38 |
+ (validated) vardbapi.aux_get method. |
39 |
+ |
40 |
+ For performance reasons, the match method only supports package |
41 |
+ name and version constraints. |
42 |
+ """ |
43 |
+ |
44 |
+ _copy_attrs = ('cpv_exists', |
45 |
+ '_aux_cache_keys', '_cpv_sort_ascending') |
46 |
+ |
47 |
+ def __init__(self, vardb): |
48 |
+ self._vardb = vardb |
49 |
+ |
50 |
+ for k in self._copy_attrs: |
51 |
+ setattr(self, k, getattr(vardb, k)) |
52 |
+ |
53 |
+ self._cp_map = None |
54 |
+ |
55 |
+ def cp_all(self): |
56 |
+ """ |
57 |
+ Returns an ordered iterator instead of a list, so that search |
58 |
+ results can be displayed incrementally. |
59 |
+ """ |
60 |
+ if self._cp_map is not None: |
61 |
+ return iter(sorted(self._cp_map)) |
62 |
+ |
63 |
+ return self._iter_cp_all() |
64 |
+ |
65 |
+ def _iter_cp_all(self): |
66 |
+ self._cp_map = cp_map = {} |
67 |
+ previous_cp = None |
68 |
+ for cpv in self._vardb._iter_cpv_all(sort = True): |
69 |
+ cp = portage.cpv_getkey(cpv) |
70 |
+ if cp is not None: |
71 |
+ cp_list = cp_map.get(cp) |
72 |
+ if cp_list is None: |
73 |
+ cp_list = [] |
74 |
+ cp_map[cp] = cp_list |
75 |
+ cp_list.append(_pkg_str(cpv)) |
76 |
+ if previous_cp is not None and \ |
77 |
+ previous_cp != cp: |
78 |
+ yield previous_cp |
79 |
+ previous_cp = cp |
80 |
+ |
81 |
+ if previous_cp is not None: |
82 |
+ yield previous_cp |
83 |
+ |
84 |
+ def match(self, atom): |
85 |
+ """ |
86 |
+ For performance reasons, only package name and version |
87 |
+ constraints are supported. |
88 |
+ """ |
89 |
+ if not isinstance(atom, Atom): |
90 |
+ atom = Atom(atom) |
91 |
+ cp_list = self._cp_map.get(atom.cp) |
92 |
+ if cp_list is None: |
93 |
+ return [] |
94 |
+ self._vardb._cpv_sort_ascending(cp_list) |
95 |
+ return portage.match_from_list(atom, cp_list) |
96 |
+ |
97 |
+ def aux_get(self, cpv, attrs, myrepo = None): |
98 |
+ pkg_data = self._vardb._aux_cache["packages"].get(cpv) |
99 |
+ if not isinstance(pkg_data, tuple) or \ |
100 |
+ len(pkg_data) != 2 or \ |
101 |
+ not isinstance(pkg_data[1], dict): |
102 |
+ pkg_data = None |
103 |
+ if pkg_data is None: |
104 |
+ # It may be missing from _aux_cache due to |
105 |
+ # _aux_cache_threshold. |
106 |
+ return self._vardb.aux_get(cpv, attrs) |
107 |
+ metadata = pkg_data[1] |
108 |
+ return [metadata.get(k, "") for k in attrs] |
109 |
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py |
110 |
index e21135a..37504e8 100644 |
111 |
--- a/pym/portage/dbapi/vartree.py |
112 |
+++ b/pym/portage/dbapi/vartree.py |
113 |
@@ -422,6 +422,9 @@ class vardbapi(dbapi): |
114 |
(generally this is only necessary in critical sections that |
115 |
involve merge or unmerge of packages). |
116 |
""" |
117 |
+ return list(self._iter_cpv_all(use_cache=use_cache)) |
118 |
+ |
119 |
+ def _iter_cpv_all(self, use_cache = True, sort = False): |
120 |
returnme = [] |
121 |
basepath = os.path.join(self._eroot, VDB_PATH) + os.path.sep |
122 |
|
123 |
@@ -438,12 +441,21 @@ class vardbapi(dbapi): |
124 |
del e |
125 |
return [] |
126 |
|
127 |
- for x in listdir(basepath, EmptyOnError=1, ignorecvs=1, dirsonly=1): |
128 |
+ catdirs = listdir(basepath, EmptyOnError=1, ignorecvs=1, dirsonly=1) |
129 |
+ if sort: |
130 |
+ catdirs.sort() |
131 |
+ |
132 |
+ for x in catdirs: |
133 |
if self._excluded_dirs.match(x) is not None: |
134 |
continue |
135 |
if not self._category_re.match(x): |
136 |
continue |
137 |
- for y in listdir(basepath + x, EmptyOnError=1, dirsonly=1): |
138 |
+ |
139 |
+ pkgdirs = listdir(basepath + x, EmptyOnError=1, dirsonly=1) |
140 |
+ if sort: |
141 |
+ pkgdirs.sort() |
142 |
+ |
143 |
+ for y in pkgdirs: |
144 |
if self._excluded_dirs.match(y) is not None: |
145 |
continue |
146 |
subpath = x + "/" + y |
147 |
@@ -455,9 +467,8 @@ class vardbapi(dbapi): |
148 |
except InvalidData: |
149 |
self.invalidentry(self.getpath(subpath)) |
150 |
continue |
151 |
- returnme.append(subpath) |
152 |
|
153 |
- return returnme |
154 |
+ yield subpath |
155 |
|
156 |
def cp_all(self, use_cache=1): |
157 |
mylist = self.cpv_all(use_cache=use_cache) |
158 |
-- |
159 |
2.0.4 |