Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH 3/5] Add IndexedPortdb class.
Date: Sat, 01 Nov 2014 22:46:48
Message-Id: 1414881983-19877-4-git-send-email-zmedico@gentoo.org
In Reply to: [gentoo-portage-dev] by Zac Medico
1 The IndexedPortdb class uses pkg_desc_index to optimize searchs for
2 package names and descriptions. If the package description index is
3 missing from a particular repository, then all metadata for that
4 repository is obtained using the normal pordbapi.aux_get method.
5
6 This class only implements a subset of portdbapi functionality that is
7 useful for searching pkg_desc_index incrementally. For this reason,
8 the cp_all method returns an ordered iterator instead of a list, so
9 that search results can be displayed incrementally.
10
11 X-Gentoo-Bug: 525718
12 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=525718
13 ---
14 pym/portage/dbapi/IndexedPortdb.py | 151 +++++++++++++++++++++++++++++++++++++
15 1 file changed, 151 insertions(+)
16 create mode 100644 pym/portage/dbapi/IndexedPortdb.py
17
18 diff --git a/pym/portage/dbapi/IndexedPortdb.py b/pym/portage/dbapi/IndexedPortdb.py
19 new file mode 100644
20 index 0000000..4fb2cf1
21 --- /dev/null
22 +++ b/pym/portage/dbapi/IndexedPortdb.py
23 @@ -0,0 +1,151 @@
24 +# Copyright 2014 Gentoo Foundation
25 +# Distributed under the terms of the GNU General Public License v2
26 +
27 +import errno
28 +import io
29 +import functools
30 +import operator
31 +import os
32 +
33 +import portage
34 +from portage import _encodings
35 +from portage.dep import Atom
36 +from portage.exception import FileNotFound
37 +from portage.cache.index.IndexStreamIterator import IndexStreamIterator
38 +from portage.cache.index.pkg_desc_index import pkg_desc_index_line_read
39 +from portage.util.iterators.MultiIterGroupBy import MultiIterGroupBy
40 +from portage.versions import _pkg_str
41 +
42 +class IndexedPortdb(object):
43 + """
44 + A portdbapi interface that uses a package description index to
45 + improve performance. If the description index is missing for a
46 + particular repository, then all metadata for that repository is
47 + obtained using the normal pordbapi.aux_get method.
48 +
49 + For performance reasons, the match method only supports package
50 + name and version constraints. For the same reason, the xmatch
51 + method is not implemented.
52 + """
53 +
54 + _copy_attrs = ('cpv_exists', 'findname', 'getFetchMap',
55 + '_aux_cache_keys', '_cpv_sort_ascending',
56 + '_have_root_eclass_dir')
57 +
58 + def __init__(self, portdb):
59 +
60 + self._portdb = portdb
61 +
62 + for k in self._copy_attrs:
63 + setattr(self, k, getattr(portdb, k))
64 +
65 + self._desc_cache = None
66 + self._cp_map = None
67 +
68 + def _init_index(self):
69 +
70 + cp_map = {}
71 + desc_cache = {}
72 + self._desc_cache = desc_cache
73 + self._cp_map = cp_map
74 +
75 + streams = []
76 + for repo_path in self._portdb.porttrees:
77 + outside_repo = os.path.join(self._portdb.depcachedir,
78 + repo_path.lstrip(os.sep))
79 + filenames = []
80 + for parent_dir in (repo_path, outside_repo):
81 + filenames.append(os.path.join(parent_dir,
82 + "metadata", "pkg_desc_index"))
83 +
84 + repo_name = self._portdb.getRepositoryName(repo_path)
85 +
86 + try:
87 + f = None
88 + for filename in filenames:
89 + try:
90 + f = io.open(filename,
91 + encoding=_encodings["repo.content"])
92 + except IOError as e:
93 + if e.errno not in (errno.ENOENT, errno.ESTALE):
94 + raise
95 + else:
96 + break
97 +
98 + if f is None:
99 + raise FileNotFound(filename)
100 +
101 + streams.append(iter(IndexStreamIterator(f,
102 + functools.partial(pkg_desc_index_line_read,
103 + repo = repo_name))))
104 + except FileNotFound:
105 +
106 + # No descriptions index was found, so populate
107 + # cp_map the slow way.
108 + for cp in self._portdb.cp_all(trees=[repo_path]):
109 +
110 + cp_list = cp_map.get(cp)
111 + if cp_list is None:
112 + cp_list = []
113 + cp_map[cp] = cp_list
114 + for cpv in self._portdb.cp_list(
115 + cp, mytree = repo_path):
116 + cp_list.append(_pkg_str(cpv, repo = repo_name))
117 +
118 + # Create a sorted queue that will be merged with the
119 + # sorted/grouped results from MultiIterGroupBy as they
120 + # become available.
121 + yield_queue = sorted(cp_map, reverse = True)
122 +
123 + for cp_group in MultiIterGroupBy(streams,
124 + key = operator.attrgetter("cp")):
125 +
126 + new_cp = None
127 + cp_list = cp_map.get(cp_group[0].cp)
128 + if cp_list is None:
129 + new_cp = cp_group[0].cp
130 + cp_list = []
131 + cp_map[cp_group[0].cp] = cp_list
132 +
133 + for entry in cp_group:
134 + cp_list.extend(entry.cpv_list)
135 + for cpv in entry.cpv_list:
136 + desc_cache[cpv] = entry.desc
137 +
138 + if new_cp is not None:
139 + while yield_queue and yield_queue[-1] < new_cp:
140 + yield yield_queue.pop()
141 + yield cp_group[0].cp
142 +
143 + while yield_queue:
144 + yield yield_queue.pop()
145 +
146 + def cp_all(self):
147 + """
148 + Returns an ordered iterator instead of a list, so that search
149 + results can be displayed incrementally.
150 + """
151 + if self._cp_map is None:
152 + return self._init_index()
153 + return iter(sorted(self._cp_map))
154 +
155 + def match(self, atom):
156 + """
157 + For performance reasons, only package name and version
158 + constraints are supported.
159 + """
160 + if not isinstance(atom, Atom):
161 + atom = Atom(atom)
162 + cp_list = self._cp_map.get(atom.cp)
163 + if cp_list is None:
164 + return []
165 + self._portdb._cpv_sort_ascending(cp_list)
166 + return portage.match_from_list(atom, cp_list)
167 +
168 + def aux_get(self, cpv, attrs, myrepo = None):
169 + if len(attrs) == 1 and attrs[0] == "DESCRIPTION":
170 + try:
171 + return [self._desc_cache[cpv]]
172 + except KeyError:
173 + pass
174 + return self._portdb.aux_get(cpv, attrs)
175 --
176 2.0.4

Replies

Subject Author
[gentoo-portage-dev] [PATCH 3/5 v2] Add IndexedPortdb class. Zac Medico <zmedico@g.o>