diff options
Diffstat (limited to 'bitbake/lib/prserv/serv.py')
-rw-r--r-- | bitbake/lib/prserv/serv.py | 134 |
1 files changed, 117 insertions, 17 deletions
diff --git a/bitbake/lib/prserv/serv.py b/bitbake/lib/prserv/serv.py index dc4be5b620..05573d06cc 100644 --- a/bitbake/lib/prserv/serv.py +++ b/bitbake/lib/prserv/serv.py | |||
@@ -12,6 +12,7 @@ import sqlite3 | |||
12 | import prserv | 12 | import prserv |
13 | import prserv.db | 13 | import prserv.db |
14 | import errno | 14 | import errno |
15 | from . import create_async_client, revision_smaller, increase_revision | ||
15 | import bb.asyncrpc | 16 | import bb.asyncrpc |
16 | 17 | ||
17 | logger = logging.getLogger("BitBake.PRserv") | 18 | logger = logging.getLogger("BitBake.PRserv") |
@@ -51,8 +52,9 @@ class PRServerClient(bb.asyncrpc.AsyncServerConnection): | |||
51 | version = request["version"] | 52 | version = request["version"] |
52 | pkgarch = request["pkgarch"] | 53 | pkgarch = request["pkgarch"] |
53 | checksum = request["checksum"] | 54 | checksum = request["checksum"] |
55 | history = request["history"] | ||
54 | 56 | ||
55 | value = self.server.table.find_value(version, pkgarch, checksum) | 57 | value = self.server.table.find_value(version, pkgarch, checksum, history) |
56 | return {"value": value} | 58 | return {"value": value} |
57 | 59 | ||
58 | async def handle_test_package(self, request): | 60 | async def handle_test_package(self, request): |
@@ -68,22 +70,110 @@ class PRServerClient(bb.asyncrpc.AsyncServerConnection): | |||
68 | version = request["version"] | 70 | version = request["version"] |
69 | pkgarch = request["pkgarch"] | 71 | pkgarch = request["pkgarch"] |
70 | 72 | ||
71 | value = self.server.table.find_max_value(version, pkgarch) | 73 | value = self.server.table.find_package_max_value(version, pkgarch) |
72 | return {"value": value} | 74 | return {"value": value} |
73 | 75 | ||
74 | async def handle_get_pr(self, request): | 76 | async def handle_get_pr(self, request): |
75 | version = request["version"] | 77 | version = request["version"] |
76 | pkgarch = request["pkgarch"] | 78 | pkgarch = request["pkgarch"] |
77 | checksum = request["checksum"] | 79 | checksum = request["checksum"] |
80 | history = request["history"] | ||
78 | 81 | ||
79 | response = None | 82 | if self.upstream_client is None: |
80 | try: | 83 | value = self.server.table.get_value(version, pkgarch, checksum, history) |
81 | value = self.server.table.get_value(version, pkgarch, checksum) | 84 | return {"value": value} |
82 | response = {"value": value} | ||
83 | except prserv.NotFoundError: | ||
84 | self.logger.error("failure storing value in database for (%s, %s)",version, checksum) | ||
85 | 85 | ||
86 | return response | 86 | # We have an upstream server. |
87 | # Check whether the local server already knows the requested configuration. | ||
88 | # If the configuration is a new one, the generated value we will add will | ||
89 | # depend on what's on the upstream server. That's why we're calling find_value() | ||
90 | # instead of get_value() directly. | ||
91 | |||
92 | value = self.server.table.find_value(version, pkgarch, checksum, history) | ||
93 | upstream_max = await self.upstream_client.max_package_pr(version, pkgarch) | ||
94 | |||
95 | if value is not None: | ||
96 | |||
97 | # The configuration is already known locally. | ||
98 | |||
99 | if history: | ||
100 | value = self.server.table.get_value(version, pkgarch, checksum, history) | ||
101 | else: | ||
102 | existing_value = value | ||
103 | # In "no history", we need to make sure the value doesn't decrease | ||
104 | # and is at least greater than the maximum upstream value | ||
105 | # and the maximum local value | ||
106 | |||
107 | local_max = self.server.table.find_package_max_value(version, pkgarch) | ||
108 | if revision_smaller(value, local_max): | ||
109 | value = increase_revision(local_max) | ||
110 | |||
111 | if revision_smaller(value, upstream_max): | ||
112 | # Ask upstream whether it knows the checksum | ||
113 | upstream_value = await self.upstream_client.test_pr(version, pkgarch, checksum) | ||
114 | if upstream_value is None: | ||
115 | # Upstream doesn't have our checksum, let create a new one | ||
116 | value = upstream_max + ".0" | ||
117 | else: | ||
118 | # Fine to take the same value as upstream | ||
119 | value = upstream_max | ||
120 | |||
121 | if not value == existing_value and not self.server.read_only: | ||
122 | self.server.table.store_value(version, pkgarch, checksum, value) | ||
123 | |||
124 | return {"value": value} | ||
125 | |||
126 | # The configuration is a new one for the local server | ||
127 | # Let's ask the upstream server whether it knows it | ||
128 | |||
129 | known_upstream = await self.upstream_client.test_package(version, pkgarch) | ||
130 | |||
131 | if not known_upstream: | ||
132 | |||
133 | # The package is not known upstream, must be a local-only package | ||
134 | # Let's compute the PR number using the local-only method | ||
135 | |||
136 | value = self.server.table.get_value(version, pkgarch, checksum, history) | ||
137 | return {"value": value} | ||
138 | |||
139 | # The package is known upstream, let's ask the upstream server | ||
140 | # whether it knows our new output hash | ||
141 | |||
142 | value = await self.upstream_client.test_pr(version, pkgarch, checksum) | ||
143 | |||
144 | if value is not None: | ||
145 | |||
146 | # Upstream knows this output hash, let's store it and use it too. | ||
147 | |||
148 | if not self.server.read_only: | ||
149 | self.server.table.store_value(version, pkgarch, checksum, value) | ||
150 | # If the local server is read only, won't be able to store the new | ||
151 | # value in the database and will have to keep asking the upstream server | ||
152 | return {"value": value} | ||
153 | |||
154 | # The output hash doesn't exist upstream, get the most recent number from upstream (x) | ||
155 | # Then, we want to have a new PR value for the local server: x.y | ||
156 | |||
157 | upstream_max = await self.upstream_client.max_package_pr(version, pkgarch) | ||
158 | # Here we know that the package is known upstream, so upstream_max can't be None | ||
159 | subvalue = self.server.table.find_new_subvalue(version, pkgarch, upstream_max) | ||
160 | |||
161 | if not self.server.read_only: | ||
162 | self.server.table.store_value(version, pkgarch, checksum, subvalue) | ||
163 | |||
164 | return {"value": subvalue} | ||
165 | |||
166 | async def process_requests(self): | ||
167 | if self.server.upstream is not None: | ||
168 | self.upstream_client = await create_async_client(self.server.upstream) | ||
169 | else: | ||
170 | self.upstream_client = None | ||
171 | |||
172 | try: | ||
173 | await super().process_requests() | ||
174 | finally: | ||
175 | if self.upstream_client is not None: | ||
176 | await self.upstream_client.close() | ||
87 | 177 | ||
88 | async def handle_import_one(self, request): | 178 | async def handle_import_one(self, request): |
89 | response = None | 179 | response = None |
@@ -92,8 +182,9 @@ class PRServerClient(bb.asyncrpc.AsyncServerConnection): | |||
92 | pkgarch = request["pkgarch"] | 182 | pkgarch = request["pkgarch"] |
93 | checksum = request["checksum"] | 183 | checksum = request["checksum"] |
94 | value = request["value"] | 184 | value = request["value"] |
185 | history = request["history"] | ||
95 | 186 | ||
96 | value = self.server.table.importone(version, pkgarch, checksum, value) | 187 | value = self.server.table.importone(version, pkgarch, checksum, value, history) |
97 | if value is not None: | 188 | if value is not None: |
98 | response = {"value": value} | 189 | response = {"value": value} |
99 | 190 | ||
@@ -104,9 +195,10 @@ class PRServerClient(bb.asyncrpc.AsyncServerConnection): | |||
104 | pkgarch = request["pkgarch"] | 195 | pkgarch = request["pkgarch"] |
105 | checksum = request["checksum"] | 196 | checksum = request["checksum"] |
106 | colinfo = request["colinfo"] | 197 | colinfo = request["colinfo"] |
198 | history = request["history"] | ||
107 | 199 | ||
108 | try: | 200 | try: |
109 | (metainfo, datainfo) = self.server.table.export(version, pkgarch, checksum, colinfo) | 201 | (metainfo, datainfo) = self.server.table.export(version, pkgarch, checksum, colinfo, history) |
110 | except sqlite3.Error as exc: | 202 | except sqlite3.Error as exc: |
111 | self.logger.error(str(exc)) | 203 | self.logger.error(str(exc)) |
112 | metainfo = datainfo = None | 204 | metainfo = datainfo = None |
@@ -117,11 +209,12 @@ class PRServerClient(bb.asyncrpc.AsyncServerConnection): | |||
117 | return {"readonly": self.server.read_only} | 209 | return {"readonly": self.server.read_only} |
118 | 210 | ||
119 | class PRServer(bb.asyncrpc.AsyncServer): | 211 | class PRServer(bb.asyncrpc.AsyncServer): |
120 | def __init__(self, dbfile, read_only=False): | 212 | def __init__(self, dbfile, read_only=False, upstream=None): |
121 | super().__init__(logger) | 213 | super().__init__(logger) |
122 | self.dbfile = dbfile | 214 | self.dbfile = dbfile |
123 | self.table = None | 215 | self.table = None |
124 | self.read_only = read_only | 216 | self.read_only = read_only |
217 | self.upstream = upstream | ||
125 | 218 | ||
126 | def accept_client(self, socket): | 219 | def accept_client(self, socket): |
127 | return PRServerClient(socket, self) | 220 | return PRServerClient(socket, self) |
@@ -134,6 +227,9 @@ class PRServer(bb.asyncrpc.AsyncServer): | |||
134 | self.logger.info("Started PRServer with DBfile: %s, Address: %s, PID: %s" % | 227 | self.logger.info("Started PRServer with DBfile: %s, Address: %s, PID: %s" % |
135 | (self.dbfile, self.address, str(os.getpid()))) | 228 | (self.dbfile, self.address, str(os.getpid()))) |
136 | 229 | ||
230 | if self.upstream is not None: | ||
231 | self.logger.info("And upstream PRServer: %s " % (self.upstream)) | ||
232 | |||
137 | return tasks | 233 | return tasks |
138 | 234 | ||
139 | async def stop(self): | 235 | async def stop(self): |
@@ -147,14 +243,15 @@ class PRServer(bb.asyncrpc.AsyncServer): | |||
147 | self.table.sync() | 243 | self.table.sync() |
148 | 244 | ||
149 | class PRServSingleton(object): | 245 | class PRServSingleton(object): |
150 | def __init__(self, dbfile, logfile, host, port): | 246 | def __init__(self, dbfile, logfile, host, port, upstream): |
151 | self.dbfile = dbfile | 247 | self.dbfile = dbfile |
152 | self.logfile = logfile | 248 | self.logfile = logfile |
153 | self.host = host | 249 | self.host = host |
154 | self.port = port | 250 | self.port = port |
251 | self.upstream = upstream | ||
155 | 252 | ||
156 | def start(self): | 253 | def start(self): |
157 | self.prserv = PRServer(self.dbfile) | 254 | self.prserv = PRServer(self.dbfile, upstream=self.upstream) |
158 | self.prserv.start_tcp_server(socket.gethostbyname(self.host), self.port) | 255 | self.prserv.start_tcp_server(socket.gethostbyname(self.host), self.port) |
159 | self.process = self.prserv.serve_as_process(log_level=logging.WARNING) | 256 | self.process = self.prserv.serve_as_process(log_level=logging.WARNING) |
160 | 257 | ||
@@ -233,7 +330,7 @@ def run_as_daemon(func, pidfile, logfile): | |||
233 | os.remove(pidfile) | 330 | os.remove(pidfile) |
234 | os._exit(0) | 331 | os._exit(0) |
235 | 332 | ||
236 | def start_daemon(dbfile, host, port, logfile, read_only=False): | 333 | def start_daemon(dbfile, host, port, logfile, read_only=False, upstream=None): |
237 | ip = socket.gethostbyname(host) | 334 | ip = socket.gethostbyname(host) |
238 | pidfile = PIDPREFIX % (ip, port) | 335 | pidfile = PIDPREFIX % (ip, port) |
239 | try: | 336 | try: |
@@ -249,7 +346,7 @@ def start_daemon(dbfile, host, port, logfile, read_only=False): | |||
249 | 346 | ||
250 | dbfile = os.path.abspath(dbfile) | 347 | dbfile = os.path.abspath(dbfile) |
251 | def daemon_main(): | 348 | def daemon_main(): |
252 | server = PRServer(dbfile, read_only=read_only) | 349 | server = PRServer(dbfile, read_only=read_only, upstream=upstream) |
253 | server.start_tcp_server(ip, port) | 350 | server.start_tcp_server(ip, port) |
254 | server.serve_forever() | 351 | server.serve_forever() |
255 | 352 | ||
@@ -336,6 +433,9 @@ def auto_start(d): | |||
336 | 433 | ||
337 | host = host_params[0].strip().lower() | 434 | host = host_params[0].strip().lower() |
338 | port = int(host_params[1]) | 435 | port = int(host_params[1]) |
436 | |||
437 | upstream = d.getVar("PRSERV_UPSTREAM") or None | ||
438 | |||
339 | if is_local_special(host, port): | 439 | if is_local_special(host, port): |
340 | import bb.utils | 440 | import bb.utils |
341 | cachedir = (d.getVar("PERSISTENT_DIR") or d.getVar("CACHE")) | 441 | cachedir = (d.getVar("PERSISTENT_DIR") or d.getVar("CACHE")) |
@@ -350,7 +450,7 @@ def auto_start(d): | |||
350 | auto_shutdown() | 450 | auto_shutdown() |
351 | if not singleton: | 451 | if not singleton: |
352 | bb.utils.mkdirhier(cachedir) | 452 | bb.utils.mkdirhier(cachedir) |
353 | singleton = PRServSingleton(os.path.abspath(dbfile), os.path.abspath(logfile), host, port) | 453 | singleton = PRServSingleton(os.path.abspath(dbfile), os.path.abspath(logfile), host, port, upstream) |
354 | singleton.start() | 454 | singleton.start() |
355 | if singleton: | 455 | if singleton: |
356 | host = singleton.host | 456 | host = singleton.host |