Merge lp:~julian-edwards/launchpad/build-queue-sizes-bug-609904 into lp:launchpad

Proposed by Julian Edwards
Status: Merged
Approved by: Māris Fogels
Approved revision: no longer in the source branch.
Merged at revision: 11289
Proposed branch: lp:~julian-edwards/launchpad/build-queue-sizes-bug-609904
Merge into: lp:launchpad
Diff against target: 75 lines (+28/-5)
2 files modified
lib/lp/buildmaster/doc/builder.txt (+21/-1)
lib/lp/buildmaster/model/builder.py (+7/-4)
To merge this branch: bzr merge lp:~julian-edwards/launchpad/build-queue-sizes-bug-609904
Reviewer Review Type Date Requested Status
Māris Fogels (community) code Approve
Review via email: mp+31647@code.launchpad.net

Description of the change

= Summary =
Put pending builds that have virtualized=False in the virtual build queues on
/builders

== Proposed fix ==
IBuilderSet.getBuildQueueSizes() is horribly broken because
BuildQueue.virtualized can be True, False or None. If it's None then the
query will potentially return three groups instead of the expected two, and
because of the bad code in the following "for" loop it will overwrite the
dictionary entry for "nonvirt" depending on which group it sees first in the
results iteration.

== Implementation details ==
Simple fix in the query to coalesce the result so that if it's NULL we turn it
into a True. Also made the inline "if" more explicit.

== Tests ==
bin/test -cvvt builder.txt

== Demo and Q/A ==
Easy to check on edge, there's about 160 pending translations builds
erroneously showing up in the distro builders queue right now!

= Launchpad lint =

Checking for conflicts and issues in changed files.

To post a comment you must log in.
Revision history for this message
Māris Fogels (mars) wrote :

Hi Julian,

I have a bit of difficulty reviewing this without domain-specific knowledge, so I'll trust you that the code is ok. But I did have a question about the tests.

You see, I'm a bit confused by the doc/ directory and the files within. When I am reading a documentation file I don't care what the 'virtualized' flag does, I just care that it exists. I also don't want to read the gritty details of how it behaves correctly when a certain bug is present (which is what the new doctest code is for). The implementation details and bugfix test should be off in a unit test somewhere.

So, is the doctest the right place to exercise the bugfix? What is the purpose of doc/builder.txt?

I'm marking this as 'Needs Information' for now.

Maris

review: Needs Information (code)
Revision history for this message
Julian Edwards (julian-edwards) wrote :

Thanks for the review Maris.

<bigjools> mars: thank you
<bigjools> mars: so, no, the doctest is absolutely not the right place for
that test but I don't have the time to convert that all to unit tests and I am
loathe to write a new unit test and not include the existing ones.

I'm happy to file a cleanup bug about it.

Revision history for this message
Māris Fogels (mars) wrote :

As discussed on IRC: I'm marking this as able to land now, but on the condition that someone be scheduled to rewrite this doctest section into a buildmaster unit test. I am not willing to let the doctests change in this way.

(We probably want an XXX line for bookkeeping and kanban)

Maris

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/buildmaster/doc/builder.txt'
--- lib/lp/buildmaster/doc/builder.txt 2010-06-25 08:45:00 +0000
+++ lib/lp/buildmaster/doc/builder.txt 2010-08-03 17:51:03 +0000
@@ -1,3 +1,8 @@
1XXX Julian 2010-08-03 bug=613096
2Most of this doctest is really a unit test in disguise. It should get
3re-written and unit tests moved to buildmaster/tests/test_builder.py
4
5
1=============6=============
2Builder Class7Builder Class
3=============8=============
@@ -173,12 +178,27 @@
173 >>> from lp.soyuz.interfaces.processor import IProcessorFamilySet178 >>> from lp.soyuz.interfaces.processor import IProcessorFamilySet
174 >>> i386_family = getUtility(IProcessorFamilySet).getByName('x86')179 >>> i386_family = getUtility(IProcessorFamilySet).getByName('x86')
175 >>> recipe_bq.processor = i386_family.processors[0]180 >>> recipe_bq.processor = i386_family.processors[0]
181 >>> recipe_bq.virtualized = True
182 >>> transaction.commit()
176 183
177 >>> transaction.commit()
178 >>> queue_sizes = builderset.getBuildQueueSizes()184 >>> queue_sizes = builderset.getBuildQueueSizes()
179 >>> print queue_sizes['virt']['386']185 >>> print queue_sizes['virt']['386']
180 (1L, datetime.timedelta(0, 64))186 (1L, datetime.timedelta(0, 64))
181187
188Any BuildQueues with a null `virtualized` property are considered virtual
189by default.
190
191 >>> recipe_bq = factory.makeSourcePackageRecipeBuildJob()
192 >>> recipe_bq.virtualized = None
193 >>> recipe_bq.processor = i386_family.processors[0]
194 >>> transaction.commit()
195 >>> queue_sizes = builderset.getBuildQueueSizes()
196
197The virtual queue size has increased accordingly:
198
199 >>> print queue_sizes['virt']['386']
200 (2L, datetime.timedelta(0, 128))
201
182202
183Resuming buildd slaves203Resuming buildd slaves
184======================204======================
185205
=== modified file 'lib/lp/buildmaster/model/builder.py'
--- lib/lp/buildmaster/model/builder.py 2010-08-02 02:13:52 +0000
+++ lib/lp/buildmaster/model/builder.py 2010-08-03 17:51:03 +0000
@@ -24,7 +24,7 @@
2424
25from sqlobject import (25from sqlobject import (
26 BoolCol, ForeignKey, IntCol, SQLObjectNotFound, StringCol)26 BoolCol, ForeignKey, IntCol, SQLObjectNotFound, StringCol)
27from storm.expr import Count, Sum27from storm.expr import Coalesce, Count, Sum
28from storm.store import Store28from storm.store import Store
29from zope.component import getUtility29from zope.component import getUtility
30from zope.interface import implements30from zope.interface import implements
@@ -704,15 +704,18 @@
704 Count(),704 Count(),
705 Sum(BuildQueue.estimated_duration),705 Sum(BuildQueue.estimated_duration),
706 Processor,706 Processor,
707 BuildQueue.virtualized),707 Coalesce(BuildQueue.virtualized, True)),
708 Processor.id == BuildQueue.processorID,708 Processor.id == BuildQueue.processorID,
709 Job.id == BuildQueue.jobID,709 Job.id == BuildQueue.jobID,
710 Job._status == JobStatus.WAITING).group_by(710 Job._status == JobStatus.WAITING).group_by(
711 Processor, BuildQueue.virtualized)711 Processor, Coalesce(BuildQueue.virtualized, True))
712712
713 result_dict = {'virt': {}, 'nonvirt': {}}713 result_dict = {'virt': {}, 'nonvirt': {}}
714 for size, duration, processor, virtualized in results:714 for size, duration, processor, virtualized in results:
715 virt_str = 'virt' if virtualized else 'nonvirt'715 if virtualized is False:
716 virt_str = 'nonvirt'
717 else:
718 virt_str = 'virt'
716 result_dict[virt_str][processor.name] = (719 result_dict[virt_str][processor.name] = (
717 size, duration)720 size, duration)
718721