summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Watt <JPEWhacker@gmail.com>2023-11-03 08:26:33 -0600
committerRichard Purdie <richard.purdie@linuxfoundation.org>2023-11-09 17:33:03 +0000
commit3a2c5a6fa2e0081c28d5f2f43e1d9a79d093ea37 (patch)
treef596b84a7295cd8421fcee447a10e2c082b94c72
parent8cfb94c06cdfe3e6f0ec1ce0154951108bc3df94 (diff)
downloadpoky-3a2c5a6fa2e0081c28d5f2f43e1d9a79d093ea37.tar.gz
bitbake: hashserv: Add db-usage API
Adds an API to query the server for the usage of the database (e.g. how many rows are present in each table) (Bitbake rev: c9c1224447e147e0de92953bc85cea75670b898c) Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rwxr-xr-xbitbake/bin/bitbake-hashclient16
-rw-r--r--bitbake/lib/hashserv/client.py5
-rw-r--r--bitbake/lib/hashserv/server.py5
-rw-r--r--bitbake/lib/hashserv/sqlalchemy.py14
-rw-r--r--bitbake/lib/hashserv/sqlite.py37
-rw-r--r--bitbake/lib/hashserv/tests.py9
6 files changed, 86 insertions, 0 deletions
diff --git a/bitbake/bin/bitbake-hashclient b/bitbake/bin/bitbake-hashclient
index cfbc197e52..5d65c7bc56 100755
--- a/bitbake/bin/bitbake-hashclient
+++ b/bitbake/bin/bitbake-hashclient
@@ -161,6 +161,19 @@ def main():
161 r = client.delete_user(args.username) 161 r = client.delete_user(args.username)
162 print_user(r) 162 print_user(r)
163 163
164 def handle_get_db_usage(args, client):
165 usage = client.get_db_usage()
166 print(usage)
167 tables = sorted(usage.keys())
168 print("{name:20}| {rows:20}".format(name="Table name", rows="Rows"))
169 print(("-" * 20) + "+" + ("-" * 20))
170 for t in tables:
171 print("{name:20}| {rows:<20}".format(name=t, rows=usage[t]["rows"]))
172 print()
173
174 total_rows = sum(t["rows"] for t in usage.values())
175 print(f"Total rows: {total_rows}")
176
164 parser = argparse.ArgumentParser(description='Hash Equivalence Client') 177 parser = argparse.ArgumentParser(description='Hash Equivalence Client')
165 parser.add_argument('--address', default=DEFAULT_ADDRESS, help='Server address (default "%(default)s")') 178 parser.add_argument('--address', default=DEFAULT_ADDRESS, help='Server address (default "%(default)s")')
166 parser.add_argument('--log', default='WARNING', help='Set logging level') 179 parser.add_argument('--log', default='WARNING', help='Set logging level')
@@ -223,6 +236,9 @@ def main():
223 delete_user_parser.add_argument("--username", "-u", help="Username", required=True) 236 delete_user_parser.add_argument("--username", "-u", help="Username", required=True)
224 delete_user_parser.set_defaults(func=handle_delete_user) 237 delete_user_parser.set_defaults(func=handle_delete_user)
225 238
239 db_usage_parser = subparsers.add_parser('get-db-usage', help="Database Usage")
240 db_usage_parser.set_defaults(func=handle_get_db_usage)
241
226 args = parser.parse_args() 242 args = parser.parse_args()
227 243
228 logger = logging.getLogger('hashserv') 244 logger = logging.getLogger('hashserv')
diff --git a/bitbake/lib/hashserv/client.py b/bitbake/lib/hashserv/client.py
index 4457f8e50d..5e0a462b1c 100644
--- a/bitbake/lib/hashserv/client.py
+++ b/bitbake/lib/hashserv/client.py
@@ -186,6 +186,10 @@ class AsyncClient(bb.asyncrpc.AsyncClient):
186 self.saved_become_user = username 186 self.saved_become_user = username
187 return result 187 return result
188 188
189 async def get_db_usage(self):
190 await self._set_mode(self.MODE_NORMAL)
191 return (await self.invoke({"get-db-usage": {}}))["usage"]
192
189 193
190class Client(bb.asyncrpc.Client): 194class Client(bb.asyncrpc.Client):
191 def __init__(self, username=None, password=None): 195 def __init__(self, username=None, password=None):
@@ -214,6 +218,7 @@ class Client(bb.asyncrpc.Client):
214 "new_user", 218 "new_user",
215 "delete_user", 219 "delete_user",
216 "become_user", 220 "become_user",
221 "get_db_usage",
217 ) 222 )
218 223
219 def _get_async_client(self): 224 def _get_async_client(self):
diff --git a/bitbake/lib/hashserv/server.py b/bitbake/lib/hashserv/server.py
index ca419a1abf..c5b9797e4e 100644
--- a/bitbake/lib/hashserv/server.py
+++ b/bitbake/lib/hashserv/server.py
@@ -249,6 +249,7 @@ class ServerClient(bb.asyncrpc.AsyncServerConnection):
249 "get-outhash": self.handle_get_outhash, 249 "get-outhash": self.handle_get_outhash,
250 "get-stream": self.handle_get_stream, 250 "get-stream": self.handle_get_stream,
251 "get-stats": self.handle_get_stats, 251 "get-stats": self.handle_get_stats,
252 "get-db-usage": self.handle_get_db_usage,
252 # Not always read-only, but internally checks if the server is 253 # Not always read-only, but internally checks if the server is
253 # read-only 254 # read-only
254 "report": self.handle_report, 255 "report": self.handle_report,
@@ -567,6 +568,10 @@ class ServerClient(bb.asyncrpc.AsyncServerConnection):
567 oldest = datetime.now() - timedelta(seconds=-max_age) 568 oldest = datetime.now() - timedelta(seconds=-max_age)
568 return {"count": await self.db.clean_unused(oldest)} 569 return {"count": await self.db.clean_unused(oldest)}
569 570
571 @permissions(DB_ADMIN_PERM)
572 async def handle_get_db_usage(self, request):
573 return {"usage": await self.db.get_usage()}
574
570 # The authentication API is always allowed 575 # The authentication API is always allowed
571 async def handle_auth(self, request): 576 async def handle_auth(self, request):
572 username = str(request["username"]) 577 username = str(request["username"])
diff --git a/bitbake/lib/hashserv/sqlalchemy.py b/bitbake/lib/hashserv/sqlalchemy.py
index bfd8a8446e..818b51951b 100644
--- a/bitbake/lib/hashserv/sqlalchemy.py
+++ b/bitbake/lib/hashserv/sqlalchemy.py
@@ -27,6 +27,7 @@ from sqlalchemy import (
27 and_, 27 and_,
28 delete, 28 delete,
29 update, 29 update,
30 func,
30) 31)
31import sqlalchemy.engine 32import sqlalchemy.engine
32from sqlalchemy.orm import declarative_base 33from sqlalchemy.orm import declarative_base
@@ -401,3 +402,16 @@ class Database(object):
401 async with self.db.begin(): 402 async with self.db.begin():
402 result = await self.db.execute(statement) 403 result = await self.db.execute(statement)
403 return result.rowcount != 0 404 return result.rowcount != 0
405
406 async def get_usage(self):
407 usage = {}
408 async with self.db.begin() as session:
409 for name, table in Base.metadata.tables.items():
410 statement = select(func.count()).select_from(table)
411 self.logger.debug("%s", statement)
412 result = await self.db.execute(statement)
413 usage[name] = {
414 "rows": result.scalar(),
415 }
416
417 return usage
diff --git a/bitbake/lib/hashserv/sqlite.py b/bitbake/lib/hashserv/sqlite.py
index 414ee8ffb8..dfdccbbaa0 100644
--- a/bitbake/lib/hashserv/sqlite.py
+++ b/bitbake/lib/hashserv/sqlite.py
@@ -120,6 +120,18 @@ class Database(object):
120 self.db = sqlite3.connect(self.dbname) 120 self.db = sqlite3.connect(self.dbname)
121 self.db.row_factory = sqlite3.Row 121 self.db.row_factory = sqlite3.Row
122 122
123 with closing(self.db.cursor()) as cursor:
124 cursor.execute("SELECT sqlite_version()")
125
126 version = []
127 for v in cursor.fetchone()[0].split("."):
128 try:
129 version.append(int(v))
130 except ValueError:
131 version.append(v)
132
133 self.sqlite_version = tuple(version)
134
123 async def __aenter__(self): 135 async def __aenter__(self):
124 return self 136 return self
125 137
@@ -362,3 +374,28 @@ class Database(object):
362 ) 374 )
363 self.db.commit() 375 self.db.commit()
364 return cursor.rowcount != 0 376 return cursor.rowcount != 0
377
378 async def get_usage(self):
379 usage = {}
380 with closing(self.db.cursor()) as cursor:
381 if self.sqlite_version >= (3, 33):
382 table_name = "sqlite_schema"
383 else:
384 table_name = "sqlite_master"
385
386 cursor.execute(
387 f"""
388 SELECT name FROM {table_name} WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
389 """
390 )
391 for row in cursor.fetchall():
392 cursor.execute(
393 """
394 SELECT COUNT() FROM %s
395 """
396 % row["name"],
397 )
398 usage[row["name"]] = {
399 "rows": cursor.fetchone()[0],
400 }
401 return usage
diff --git a/bitbake/lib/hashserv/tests.py b/bitbake/lib/hashserv/tests.py
index 311b7b7772..9d5bec2454 100644
--- a/bitbake/lib/hashserv/tests.py
+++ b/bitbake/lib/hashserv/tests.py
@@ -767,6 +767,15 @@ class HashEquivalenceCommonTests(object):
767 with self.auth_perms("@user-admin") as client: 767 with self.auth_perms("@user-admin") as client:
768 become = client.become_user(client.username) 768 become = client.become_user(client.username)
769 769
770 def test_get_db_usage(self):
771 usage = self.client.get_db_usage()
772
773 self.assertTrue(isinstance(usage, dict))
774 for name in usage.keys():
775 self.assertTrue(isinstance(usage[name], dict))
776 self.assertIn("rows", usage[name])
777 self.assertTrue(isinstance(usage[name]["rows"], int))
778
770 779
771class TestHashEquivalenceUnixServer(HashEquivalenceTestSetup, HashEquivalenceCommonTests, unittest.TestCase): 780class TestHashEquivalenceUnixServer(HashEquivalenceTestSetup, HashEquivalenceCommonTests, unittest.TestCase):
772 def get_server_addr(self, server_idx): 781 def get_server_addr(self, server_idx):