forked from importers/git-importer
Collect the requests for revisions in one DB call
For smaller packages this doesn't matter as much, but for large ones the N+1 queries can sum up badly
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
from typing import Dict
|
||||
from xmlrpc.client import Boolean
|
||||
|
||||
from lib.db_revision import DBRevision
|
||||
from lib.request import Request
|
||||
|
||||
@@ -103,24 +106,57 @@ class TreeBuilder:
|
||||
def add_merge_points(self, factory_revisions):
|
||||
"""For all target revisions that accepted a request, look up the merge
|
||||
points in the source chains (ignoring the actual revision submitted for now)"""
|
||||
source_revisions = dict()
|
||||
factory_node = factory_revisions
|
||||
while factory_node:
|
||||
if factory_node.revision.request_id:
|
||||
req = Request.find(self.db, factory_node.revision.request_id)
|
||||
|
||||
class FindRequestsWalker(AbstractWalker):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.requests = set()
|
||||
|
||||
def call(self, node: TreeNode, _: Boolean) -> None:
|
||||
if not node.revision.request_id:
|
||||
return
|
||||
self.requests.add(node.revision.request_id)
|
||||
|
||||
class FindMergeWalker(AbstractWalker):
|
||||
def __init__(self, builder: TreeBuilder, requests: Dict) -> None:
|
||||
super().__init__()
|
||||
self.source_revisions = dict()
|
||||
self.builder = builder
|
||||
self.requests = requests
|
||||
|
||||
def call(self, node, is_source) -> None:
|
||||
# not going to happen, but better safe
|
||||
if is_source:
|
||||
return
|
||||
if not node.revision.request_id:
|
||||
return
|
||||
req = self.requests.get(node.revision.request_id)
|
||||
key = f"{req.source_project}/{req.source_package}"
|
||||
if key not in source_revisions:
|
||||
source_revisions[key] = self.revisions_chain(
|
||||
if key not in self.source_revisions:
|
||||
self.source_revisions[key] = self.builder.revisions_chain(
|
||||
req.source_project, req.source_package
|
||||
)
|
||||
factory_node.merged = self.find_merge(
|
||||
factory_node.revision, source_revisions[key]
|
||||
node.merged = self.builder.find_merge(
|
||||
node.revision, self.source_revisions[key]
|
||||
)
|
||||
# add a reverse lookup
|
||||
if factory_node.merged:
|
||||
factory_node.merged.merged_into = factory_node
|
||||
if node.merged:
|
||||
node.merged.merged_into = node
|
||||
|
||||
factory_node = factory_node.parent
|
||||
# walk the tree twice. First we collect all requests to be looked up
|
||||
# to avoid going into the DB a thousand times
|
||||
frqs = FindRequestsWalker()
|
||||
factory_revisions.walk(frqs)
|
||||
requests = dict()
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT * from requests WHERE id = ANY(%s)", (list(frqs.requests),)
|
||||
)
|
||||
for row in cur.fetchall():
|
||||
req = Request.from_db(row)
|
||||
requests[req.dbid] = req
|
||||
sw = FindMergeWalker(self, requests)
|
||||
factory_revisions.walk(sw)
|
||||
|
||||
def prune_loose_end(self, factory_node):
|
||||
"""Look for source revisions that end in a new root and prune them"""
|
||||
|
Reference in New Issue
Block a user