Exemplo n.º 1
0
    def generate_dependency_changes(self, collection, repo_id, sack, packages, brs):
        """
        Generates and persists dependency changes for given list of packages.
        Emits package state change events.
        """
        # pylint:disable=too-many-locals
        results = []

        build_group = self.get_build_group(collection, repo_id)
        if build_group is None:
            raise RuntimeError(
                f"No build group found for {collection.name} at repo_id {repo_id}"
            )
        gen = ((package, self.resolve_dependencies(sack, br, build_group))
               for package, br in zip(packages, brs))
        queue_size = get_config('dependency.resolver_queue_size')
        gen = util.parallel_generator(gen, queue_size=queue_size)
        pkgs_done = 0
        pkgs_reported = 0
        progres_reported_at = time.time()
        for package, (resolved, curr_problems, curr_deps) in gen:
            changes = []
            if curr_deps is not None:
                prev_build = self.get_build_for_comparison(package)
                if prev_build and prev_build.dependency_keys:
                    prev_deps = self.dependency_cache.get_by_ids(
                        prev_build.dependency_keys
                    )
                    changes = self.create_dependency_changes(
                        prev_deps, curr_deps, package_id=package.id,
                    )
            results.append(ResolutionOutput(
                package=package,
                prev_resolved=package.resolved,
                resolved=resolved,
                problems=set(curr_problems),
                changes=changes,
                # last_build_id is used to detect concurrently registered builds
                last_build_id=package.last_build_id,
            ))
            if len(results) > get_config('dependency.persist_chunk_size'):
                self.persist_resolution_output(results)
                results = []
            pkgs_done += 1
            current_time = time.time()
            time_diff = current_time - progres_reported_at
            if time_diff > get_config('dependency.perf_report_interval'):
                self.log.info(
                    "Resolution progress: resolved {} packages ({}%) ({} pkgs/min)"
                    .format(
                        pkgs_done,
                        int(pkgs_done / len(packages) * 100.0),
                        int((pkgs_done - pkgs_reported) / time_diff * 60.0)

                    )
                )
                pkgs_reported = pkgs_done
                progres_reported_at = current_time

        self.persist_resolution_output(results)
Exemplo n.º 2
0
    def generate_dependency_changes(self, collection, repo_id, sack, packages, brs):
        """
        Generates and persists dependency changes for given list of packages.
        Emits package state change events.
        """
        # pylint:disable=too-many-locals
        results = []

        build_group = self.get_build_group(collection, repo_id)
        if build_group is None:
            raise RuntimeError(
                f"No build group found for {collection.name} at repo_id {repo_id}"
            )
        gen = ((package, self.resolve_dependencies(sack, br, build_group))
               for package, br in zip(packages, brs))
        queue_size = get_config('dependency.resolver_queue_size')
        gen = util.parallel_generator(gen, queue_size=queue_size)
        pkgs_done = 0
        pkgs_reported = 0
        progres_reported_at = time.time()
        for package, (resolved, curr_problems, curr_deps) in gen:
            changes = []
            if curr_deps is not None:
                prev_build = self.get_build_for_comparison(package)
                if prev_build and prev_build.dependency_keys:
                    prev_deps = self.dependency_cache.get_by_ids(
                        prev_build.dependency_keys
                    )
                    changes = self.create_dependency_changes(
                        prev_deps, curr_deps, package_id=package.id,
                    )
            results.append(ResolutionOutput(
                package=package,
                prev_resolved=package.resolved,
                resolved=resolved,
                problems=set(curr_problems),
                changes=changes,
                # last_build_id is used to detect concurrently registered builds
                last_build_id=package.last_build_id,
            ))
            if len(results) > get_config('dependency.persist_chunk_size'):
                self.persist_resolution_output(results)
                results = []
            pkgs_done += 1
            current_time = time.time()
            time_diff = current_time - progres_reported_at
            if time_diff > get_config('dependency.perf_report_interval'):
                self.log.info(
                    "Resolution progress: resolved {} packages ({}%) ({} pkgs/min)"
                    .format(
                        pkgs_done,
                        int(pkgs_done / len(packages) * 100.0),
                        int((pkgs_done - pkgs_reported) / time_diff * 60.0)

                    )
                )
                pkgs_reported = pkgs_done
                progres_reported_at = current_time

        self.persist_resolution_output(results)
Exemplo n.º 3
0
 def generate_repo(self, collection, repo_id):
     """
     Generates new dependency changes for requested repo using given
     collection. Finishes early when base buildroot is not resolvable.
     Updates collection resolution metadata (repo_id, base_resolved) after
     finished. Commits data in increments.
     """
     total_time.reset()
     generate_dependency_changes_time.reset()
     total_time.start()
     self.log.info("Generating new repo")
     repo_descriptor = self.create_repo_descriptor(repo_id)
     self.set_descriptor_tags([repo_descriptor])
     if not repo_descriptor.build_tag:
         self.log.error('Cannot generate repo: {}'.format(repo_id))
         self.db.rollback()
         return
     packages = self.get_packages(collection)
     brs = koji_util.get_rpm_requires(self.koji_sessions['secondary'],
                                      [p.srpm_nvra for p in packages])
     brs = util.parallel_generator(brs, queue_size=None)
     try:
         sack = self.repo_cache.get_sack(repo_descriptor)
         if not sack:
             self.log.error('Cannot generate repo: {}'.format(repo_id))
             self.db.rollback()
             return
         build_group = self.get_build_group(collection)
         resolved, base_problems, _ = self.resolve_dependencies(
             sack, [], build_group)
         resolution_time.stop()
         if not resolved:
             self.log.info("Build group not resolvable for {}".format(
                 collection.name))
             collection.latest_repo_id = repo_id
             collection.latest_repo_resolved = False
             self.db.execute(BuildrootProblem.__table__.insert(),
                             [{
                                 'collection_id': collection.id,
                                 'problem': problem
                             } for problem in base_problems])
             self.db.commit()
             return
         self.log.info("Resolving dependencies...")
         resolution_time.start()
         self.generate_dependency_changes(sack, collection, packages, brs,
                                          repo_id)
         resolution_time.stop()
     finally:
         brs.stop()
     collection.latest_repo_id = repo_id
     collection.latest_repo_resolved = True
     self.db.commit()
     total_time.stop()
     total_time.display()
     generate_dependency_changes_time.display()
Exemplo n.º 4
0
    def process_builds(self):
        # pylint: disable=E1101
        builds = self.db.query(Build.id, Build.repo_id, Build.real, Build.package_id,
                               Package.name, Build.version, Build.release,
                               Package.last_build_id, Package.collection_id)\
            .join(Build.package)\
            .filter(Build.deps_resolved == None)\
            .filter(Build.repo_id != None)\
            .order_by(Build.repo_id).all()

        descriptors = [self.create_repo_descriptor(build.repo_id) for build in builds]
        self.set_descriptor_tags(descriptors)
        builds_to_process = []
        repos_to_process = []
        unavailable_build_ids = []
        for descriptor, build in izip(descriptors, builds):
            if descriptor.build_tag:
                repos_to_process.append(descriptor)
                builds_to_process.append(build)
            else:
                unavailable_build_ids.append(build.id)
        if unavailable_build_ids:
            self.db.query(Build)\
                .filter(Build.id.in_(unavailable_build_ids))\
                .update({'deps_resolved': False}, synchronize_session=False)
            self.db.commit()
        buildrequires = koji_util.get_rpm_requires(self.koji_sessions['secondary'],
                                                   [dict(name=b.name, version=b.version,
                                                         release=b.release, arch='src')
                                                    for b in builds_to_process])
        if len(builds) > 100:
            buildrequires = util.parallel_generator(buildrequires, queue_size=None)
        for repo_descriptor, group in groupby(izip(repos_to_process,
                                                   builds_to_process,
                                                   buildrequires),
                                              lambda item: item[0]):
            sack = self.repo_cache.get_sack(repo_descriptor)
            if sack:
                for _, build, brs in group:
                    build_group = self.get_build_group(build.collection_id)
                    _, _, curr_deps = self.resolve_dependencies(sack, brs, build_group)
                    try:
                        self.process_build(sack, build, curr_deps)
                        self.db.commit()
                    except (StaleDataError, ObjectDeletedError):
                        # build deleted concurrently
                        self.db.rollback()
            else:
                self.log.info("Repo id=%d not available, skipping",
                              repo_descriptor.repo_id)
            sack = None
        self.db.query(Build)\
            .filter_by(repo_id=None)\
            .filter(Build.state.in_(Build.FINISHED_STATES))\
            .update({'deps_resolved': False}, synchronize_session=False)
        self.db.commit()
Exemplo n.º 5
0
 def generate_repo(self, collection, repo_id):
     """
     Generates new dependency changes for requested repo using given
     collection. Finishes early when base buildroot is not resolvable.
     Updates collection resolution metadata (repo_id, base_resolved) after
     finished. Commits data in increments.
     """
     total_time.reset()
     generate_dependency_changes_time.reset()
     total_time.start()
     self.log.info("Generating new repo")
     repo_descriptor = self.create_repo_descriptor(repo_id)
     self.set_descriptor_tags([repo_descriptor])
     if not repo_descriptor.build_tag:
         self.log.error('Cannot generate repo: {}'.format(repo_id))
         self.db.rollback()
         return
     packages = self.get_packages(collection)
     brs = koji_util.get_rpm_requires(self.koji_sessions['secondary'],
                                      [p.srpm_nvra for p in packages])
     brs = util.parallel_generator(brs, queue_size=None)
     try:
         sack = self.repo_cache.get_sack(repo_descriptor)
         if not sack:
             self.log.error('Cannot generate repo: {}'.format(repo_id))
             self.db.rollback()
             return
         build_group = self.get_build_group(collection)
         resolved, base_problems, _ = self.resolve_dependencies(sack, [], build_group)
         resolution_time.stop()
         if not resolved:
             self.log.info("Build group not resolvable for {}"
                           .format(collection.name))
             collection.latest_repo_id = repo_id
             collection.latest_repo_resolved = False
             self.db.execute(BuildrootProblem.__table__.insert(),
                             [{'collection_id': collection.id, 'problem': problem}
                              for problem in base_problems])
             self.db.commit()
             return
         self.log.info("Resolving dependencies...")
         resolution_time.start()
         self.generate_dependency_changes(sack, collection, packages, brs, repo_id)
         resolution_time.stop()
     finally:
         brs.stop()
     collection.latest_repo_id = repo_id
     collection.latest_repo_resolved = True
     self.db.commit()
     total_time.stop()
     total_time.display()
     generate_dependency_changes_time.display()
Exemplo n.º 6
0
    def run(self):
        # pylint: disable=E1101
        unprocessed = self.db.query(Build)\
                             .filter_by(deps_processed=False)\
                             .filter(Build.repo_id != None)\
                             .options(joinedload(Build.package))\
                             .order_by(Build.repo_id).all()

        repo_ids = [repo_id for repo_id, _ in
                    itertools.groupby(unprocessed, lambda build: build.repo_id)]
        dead_repos = self.prefetch_repos(repo_ids)
        for repo_id, builds in itertools.groupby(unprocessed,
                                                 lambda build: build.repo_id):
            builds = list(builds)
            if repo_id not in dead_repos:
                with self.repo_cache.get_sack(repo_id) as sack:
                    if sack:
                        brs = util.get_rpm_requires(self.koji_session,
                                                    [b.srpm_nvra for b in builds])
                        if len(builds) > 100:
                            brs = util.parallel_generator(brs, queue_size=None)
                        gen = ((build, self.resolve_dependencies(sack, br))
                               for build, br in itertools.izip(builds, brs))
                        if len(builds) > 2:
                            gen = util.parallel_generator(gen, queue_size=10)
                        for build, result in gen:
                            _, _, curr_deps = result
                            self.process_build(sack, build, curr_deps)
                    else:
                        self.log.info("Repo id=%d not available, skipping", repo_id)
            self.db.query(Build).filter(Build.id.in_([b.id for b in builds]))\
                                .update({'deps_processed': True},
                                        synchronize_session=False)
            self.db.commit()
        self.db.query(Build)\
            .filter_by(repo_id=None)\
            .filter(Build.state.in_(Build.FINISHED_STATES))\
            .update({'deps_processed': True}, synchronize_session=False)
Exemplo n.º 7
0
    def generate_dependency_changes(self, sack, collection, packages, brs,
                                    repo_id):
        """
        Generates and persists dependency changes for given list of packages.
        Emits package state change events.
        """
        resolved_map = {}
        problems = []
        changes = []

        def persist():
            state_changes = self.check_package_state_changes(resolved_map)
            self.persist_results(resolved_map, problems, changes)
            self.db.commit()
            self.emit_package_state_changes(state_changes)

        build_group = self.get_build_group(collection)
        gen = ((package, self.resolve_dependencies(sack, br, build_group))
               for package, br in izip(packages, brs))
        queue_size = get_config('dependency.resolver_queue_size')
        gen = util.parallel_generator(gen, queue_size=queue_size)
        for package, result in gen:
            generate_dependency_changes_time.start()
            resolved_map[package.id], curr_problems, curr_deps = result
            problems += [
                dict(package_id=package.id, problem=problem)
                for problem in sorted(set(curr_problems))
            ]
            if curr_deps is not None:
                prev_build = self.get_build_for_comparison(package)
                if prev_build and prev_build.dependency_keys:
                    prev_deps = self.dependency_cache.get_by_ids(
                        self.db, prev_build.dependency_keys)
                    create_dependency_changes_time.start()
                    changes += self.create_dependency_changes(
                        prev_deps,
                        curr_deps,
                        package_id=package.id,
                        prev_build_id=prev_build.id)
                    create_dependency_changes_time.stop()
            if len(resolved_map) > get_config('dependency.persist_chunk_size'):
                persist()
                resolved_map = {}
                problems = []
                changes = []
            generate_dependency_changes_time.stop()
        persist()
Exemplo n.º 8
0
    def generate_dependency_changes(self, sack, collection, packages, brs, repo_id):
        """
        Generates and persists dependency changes for given list of packages.
        Emits package state change events.
        """
        resolved_map = {}
        problems = []
        changes = []

        def persist():
            state_changes = self.check_package_state_changes(resolved_map)
            self.persist_results(resolved_map, problems, changes)
            self.db.commit()
            self.emit_package_state_changes(state_changes)
        build_group = self.get_build_group(collection)
        gen = ((package, self.resolve_dependencies(sack, br, build_group))
               for package, br in izip(packages, brs))
        queue_size = get_config('dependency.resolver_queue_size')
        gen = util.parallel_generator(gen, queue_size=queue_size)
        for package, result in gen:
            generate_dependency_changes_time.start()
            resolved_map[package.id], curr_problems, curr_deps = result
            problems += [dict(package_id=package.id, problem=problem)
                         for problem in sorted(set(curr_problems))]
            if curr_deps is not None:
                prev_build = self.get_build_for_comparison(package)
                if prev_build and prev_build.dependency_keys:
                    prev_deps = self.dependency_cache.get_by_ids(
                        self.db, prev_build.dependency_keys)
                    create_dependency_changes_time.start()
                    changes += self.create_dependency_changes(
                        prev_deps, curr_deps, package_id=package.id,
                        prev_build_id=prev_build.id)
                    create_dependency_changes_time.stop()
            if len(resolved_map) > get_config('dependency.persist_chunk_size'):
                persist()
                resolved_map = {}
                problems = []
                changes = []
            generate_dependency_changes_time.stop()
        persist()
Exemplo n.º 9
0
 def run(self, repo_id):
     total_time.reset()
     total_time.start()
     self.log.info("Generating new repo")
     if self.prefetch_repos([repo_id]):
         self.db.rollback()
         return
     packages = self.get_packages(require_build=True)
     repo = Repo(repo_id=repo_id)
     brs = util.get_rpm_requires(self.koji_session,
                                 [p.srpm_nvra for p in packages])
     brs = util.parallel_generator(brs, queue_size=None)
     try:
         with self.repo_cache.get_sack(repo_id) as sack:
             if not sack:
                 self.log.error('Cannot generate repo: {}'.format(repo_id))
                 self.db.rollback()
                 return
             repo.base_resolved, base_problems, _ = self.resolve_dependencies(sack, [])
             resolution_time.stop()
             if not repo.base_resolved:
                 self.log.info("Build group not resolvable")
                 self.db.add(repo)
                 self.db.flush()
                 self.db.execute(BuildrootProblem.__table__.insert(),
                                 [{'repo_id': repo.repo_id, 'problem': problem}
                                  for problem in base_problems])
                 self.db.commit()
                 return
             self.log.info("Resolving dependencies...")
             resolution_time.start()
             self.generate_dependency_changes(sack, packages, brs, repo_id)
             resolution_time.stop()
     finally:
         brs.stop()
     self.db.add(repo)
     self.db.commit()
     total_time.stop()
     total_time.display()
Exemplo n.º 10
0
 def generate_dependency_changes(self, sack, packages, brs, repo_id):
     """
     Generates and persists dependency changes for given list of packages.
     Emits package state change events.
     """
     resolved_map = {}
     problems = []
     changes = []
     def persist():
         self.check_package_state_changes(resolved_map)
         self.persist_results(resolved_map, problems, changes)
         self.db.commit()
     gen = ((package, self.resolve_dependencies(sack, br))
            for package, br in itertools.izip(packages, brs))
     gen = util.parallel_generator(gen, queue_size=10)
     for package, result in gen:
         resolved_map[package.id], curr_problems, curr_deps = result
         problems += [dict(package_id=package.id, problem=problem)
                      for problem in sorted(set(curr_problems))]
         if curr_deps is not None:
             last_build = self.get_build_for_comparison(package)
             if last_build:
                 prev_deps = self.get_deps_from_db(last_build.package_id,
                                                   last_build.repo_id)
                 if prev_deps is not None:
                     create_dependency_changes_time.start()
                     changes += self.create_dependency_changes(
                         prev_deps, curr_deps, package_id=package.id,
                         prev_build_id=last_build.id)
                     create_dependency_changes_time.stop()
         if len(resolved_map) > util.config['dependency']['persist_chunk_size']:
             persist()
             resolved_map = {}
             problems = []
             changes = []
     persist()
Exemplo n.º 11
0
    def process_builds(self):
        # pylint: disable=E1101
        builds = self.db.query(Build.id, Build.repo_id, Build.real, Build.package_id,
                               Package.name, Build.version, Build.release,
                               Package.last_build_id, Package.collection_id)\
            .join(Build.package)\
            .filter(Build.deps_resolved == None)\
            .filter(Build.repo_id != None)\
            .order_by(Build.repo_id).all()

        descriptors = [
            self.create_repo_descriptor(build.repo_id) for build in builds
        ]
        self.set_descriptor_tags(descriptors)
        builds_to_process = []
        repos_to_process = []
        unavailable_build_ids = []
        for descriptor, build in izip(descriptors, builds):
            if descriptor.build_tag:
                repos_to_process.append(descriptor)
                builds_to_process.append(build)
            else:
                unavailable_build_ids.append(build.id)
        if unavailable_build_ids:
            self.db.query(Build)\
                .filter(Build.id.in_(unavailable_build_ids))\
                .update({'deps_resolved': False}, synchronize_session=False)
            self.db.commit()
        buildrequires = koji_util.get_rpm_requires(
            self.koji_sessions['secondary'], [
                dict(name=b.name,
                     version=b.version,
                     release=b.release,
                     arch='src') for b in builds_to_process
            ])
        if len(builds) > 100:
            buildrequires = util.parallel_generator(buildrequires,
                                                    queue_size=None)
        for repo_descriptor, group in groupby(
                izip(repos_to_process, builds_to_process, buildrequires),
                lambda item: item[0]):
            sack = self.repo_cache.get_sack(repo_descriptor)
            if sack:
                for _, build, brs in group:
                    build_group = self.get_build_group(build.collection_id)
                    _, _, curr_deps = self.resolve_dependencies(
                        sack, brs, build_group)
                    try:
                        self.process_build(sack, build, curr_deps)
                        self.db.commit()
                    except (StaleDataError, ObjectDeletedError):
                        # build deleted concurrently
                        self.db.rollback()
            else:
                self.log.info("Repo id=%d not available, skipping",
                              repo_descriptor.repo_id)
            sack = None
        self.db.query(Build)\
            .filter_by(repo_id=None)\
            .filter(Build.state.in_(Build.FINISHED_STATES))\
            .update({'deps_resolved': False}, synchronize_session=False)
        self.db.commit()