summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorJoshua Watt <JPEWhacker@gmail.com>2024-05-29 13:39:33 -0600
committerRichard Purdie <richard.purdie@linuxfoundation.org>2024-05-30 07:38:10 +0100
commite16d690e777c625f12c2838b6719fa913c159c69 (patch)
treeace40ae3b19c12297d54ceea8591b5bbb2aa0310 /bitbake
parent76a63bd031d923b0dc97ee34ae2faf595bbb98ae (diff)
downloadpoky-e16d690e777c625f12c2838b6719fa913c159c69.tar.gz
bitbake: hashserv: server: Add support for SO_REUSEPORT
SO_REUSEPORT is a socket option that allows multiple servers to listen on the same TCP port, and the kernel will automatically load balance the connections between them. This is particularly helpful for the hash server since it runs in a single thread. To take advantage of a multi-core server, multiple servers can be started in parallel with this option (up to 1 per CPU) and the kernel will load balance between them. (Bitbake rev: d72d5a7decb489e2af0ebc43cfea0ca3e4353e9b) Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rwxr-xr-xbitbake/bin/bitbake-hashserv10
-rw-r--r--bitbake/lib/bb/asyncrpc/serv.py34
-rw-r--r--bitbake/lib/hashserv/__init__.py6
3 files changed, 40 insertions, 10 deletions
diff --git a/bitbake/bin/bitbake-hashserv b/bitbake/bin/bitbake-hashserv
index 4bfb7abfbc..01503736b9 100755
--- a/bitbake/bin/bitbake-hashserv
+++ b/bitbake/bin/bitbake-hashserv
@@ -125,6 +125,11 @@ The following permissions are supported by the server:
125 default=os.environ.get("HASHSERVER_ADMIN_PASSWORD", None), 125 default=os.environ.get("HASHSERVER_ADMIN_PASSWORD", None),
126 help="Create default admin user with password ADMIN_PASSWORD ($HASHSERVER_ADMIN_PASSWORD)", 126 help="Create default admin user with password ADMIN_PASSWORD ($HASHSERVER_ADMIN_PASSWORD)",
127 ) 127 )
128 parser.add_argument(
129 "--reuseport",
130 action="store_true",
131 help="Enable SO_REUSEPORT, allowing multiple servers to bind to the same port for load balancing",
132 )
128 133
129 args = parser.parse_args() 134 args = parser.parse_args()
130 135
@@ -132,7 +137,9 @@ The following permissions are supported by the server:
132 137
133 level = getattr(logging, args.log.upper(), None) 138 level = getattr(logging, args.log.upper(), None)
134 if not isinstance(level, int): 139 if not isinstance(level, int):
135 raise ValueError("Invalid log level: %s (Try ERROR/WARNING/INFO/DEBUG)" % args.log) 140 raise ValueError(
141 "Invalid log level: %s (Try ERROR/WARNING/INFO/DEBUG)" % args.log
142 )
136 143
137 logger.setLevel(level) 144 logger.setLevel(level)
138 console = logging.StreamHandler() 145 console = logging.StreamHandler()
@@ -155,6 +162,7 @@ The following permissions are supported by the server:
155 anon_perms=anon_perms, 162 anon_perms=anon_perms,
156 admin_username=args.admin_user, 163 admin_username=args.admin_user,
157 admin_password=args.admin_password, 164 admin_password=args.admin_password,
165 reuseport=args.reuseport,
158 ) 166 )
159 server.serve_forever() 167 server.serve_forever()
160 return 0 168 return 0
diff --git a/bitbake/lib/bb/asyncrpc/serv.py b/bitbake/lib/bb/asyncrpc/serv.py
index a66117acad..46d54fb511 100644
--- a/bitbake/lib/bb/asyncrpc/serv.py
+++ b/bitbake/lib/bb/asyncrpc/serv.py
@@ -138,14 +138,20 @@ class StreamServer(object):
138 138
139 139
140class TCPStreamServer(StreamServer): 140class TCPStreamServer(StreamServer):
141 def __init__(self, host, port, handler, logger): 141 def __init__(self, host, port, handler, logger, *, reuseport=False):
142 super().__init__(handler, logger) 142 super().__init__(handler, logger)
143 self.host = host 143 self.host = host
144 self.port = port 144 self.port = port
145 self.reuseport = reuseport
145 146
146 def start(self, loop): 147 def start(self, loop):
147 self.server = loop.run_until_complete( 148 self.server = loop.run_until_complete(
148 asyncio.start_server(self.handle_stream_client, self.host, self.port) 149 asyncio.start_server(
150 self.handle_stream_client,
151 self.host,
152 self.port,
153 reuse_port=self.reuseport,
154 )
149 ) 155 )
150 156
151 for s in self.server.sockets: 157 for s in self.server.sockets:
@@ -209,11 +215,12 @@ class UnixStreamServer(StreamServer):
209 215
210 216
211class WebsocketsServer(object): 217class WebsocketsServer(object):
212 def __init__(self, host, port, handler, logger): 218 def __init__(self, host, port, handler, logger, *, reuseport=False):
213 self.host = host 219 self.host = host
214 self.port = port 220 self.port = port
215 self.handler = handler 221 self.handler = handler
216 self.logger = logger 222 self.logger = logger
223 self.reuseport = reuseport
217 224
218 def start(self, loop): 225 def start(self, loop):
219 import websockets.server 226 import websockets.server
@@ -224,6 +231,7 @@ class WebsocketsServer(object):
224 self.host, 231 self.host,
225 self.port, 232 self.port,
226 ping_interval=None, 233 ping_interval=None,
234 reuse_port=self.reuseport,
227 ) 235 )
228 ) 236 )
229 237
@@ -262,14 +270,26 @@ class AsyncServer(object):
262 self.loop = None 270 self.loop = None
263 self.run_tasks = [] 271 self.run_tasks = []
264 272
265 def start_tcp_server(self, host, port): 273 def start_tcp_server(self, host, port, *, reuseport=False):
266 self.server = TCPStreamServer(host, port, self._client_handler, self.logger) 274 self.server = TCPStreamServer(
275 host,
276 port,
277 self._client_handler,
278 self.logger,
279 reuseport=reuseport,
280 )
267 281
268 def start_unix_server(self, path): 282 def start_unix_server(self, path):
269 self.server = UnixStreamServer(path, self._client_handler, self.logger) 283 self.server = UnixStreamServer(path, self._client_handler, self.logger)
270 284
271 def start_websocket_server(self, host, port): 285 def start_websocket_server(self, host, port, reuseport=False):
272 self.server = WebsocketsServer(host, port, self._client_handler, self.logger) 286 self.server = WebsocketsServer(
287 host,
288 port,
289 self._client_handler,
290 self.logger,
291 reuseport=reuseport,
292 )
273 293
274 async def _client_handler(self, socket): 294 async def _client_handler(self, socket):
275 address = socket.address 295 address = socket.address
diff --git a/bitbake/lib/hashserv/__init__.py b/bitbake/lib/hashserv/__init__.py
index 74367eb6b4..ac891e0174 100644
--- a/bitbake/lib/hashserv/__init__.py
+++ b/bitbake/lib/hashserv/__init__.py
@@ -13,6 +13,7 @@ from bb.asyncrpc.client import parse_address, ADDR_TYPE_UNIX, ADDR_TYPE_WS
13 13
14User = namedtuple("User", ("username", "permissions")) 14User = namedtuple("User", ("username", "permissions"))
15 15
16
16def create_server( 17def create_server(
17 addr, 18 addr,
18 dbname, 19 dbname,
@@ -25,6 +26,7 @@ def create_server(
25 anon_perms=None, 26 anon_perms=None,
26 admin_username=None, 27 admin_username=None,
27 admin_password=None, 28 admin_password=None,
29 reuseport=False,
28): 30):
29 def sqlite_engine(): 31 def sqlite_engine():
30 from .sqlite import DatabaseEngine 32 from .sqlite import DatabaseEngine
@@ -60,9 +62,9 @@ def create_server(
60 s.start_unix_server(*a) 62 s.start_unix_server(*a)
61 elif typ == ADDR_TYPE_WS: 63 elif typ == ADDR_TYPE_WS:
62 url = urlparse(a[0]) 64 url = urlparse(a[0])
63 s.start_websocket_server(url.hostname, url.port) 65 s.start_websocket_server(url.hostname, url.port, reuseport=reuseport)
64 else: 66 else:
65 s.start_tcp_server(*a) 67 s.start_tcp_server(*a, reuseport=reuseport)
66 68
67 return s 69 return s
68 70