Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(968)

Side by Side Diff: third_party/buildbot_8_4p1/buildbot/status/builder.py

Issue 18429003: Utilize buildCache in a smarter way to prevent pathological disk I/O storms. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Address iannucci's comments. Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # This file is part of Buildbot. Buildbot is free software: you can 1 # This file is part of Buildbot. Buildbot is free software: you can
2 # redistribute it and/or modify it under the terms of the GNU General Public 2 # redistribute it and/or modify it under the terms of the GNU General Public
3 # License as published by the Free Software Foundation, version 2. 3 # License as published by the Free Software Foundation, version 2.
4 # 4 #
5 # This program is distributed in the hope that it will be useful, but WITHOUT 5 # This program is distributed in the hope that it will be useful, but WITHOUT
6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 7 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
8 # details. 8 # details.
9 # 9 #
10 # You should have received a copy of the GNU General Public License along with 10 # You should have received a copy of the GNU General Public License along with
11 # this program; if not, write to the Free Software Foundation, Inc., 51 11 # this program; if not, write to the Free Software Foundation, Inc., 51
12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
13 # 13 #
14 # Copyright Buildbot Team Members 14 # Copyright Buildbot Team Members
15 15
16 16
17 import weakref 17 import weakref
18 import gc 18 import gc
19 import os, re, itertools 19 import os, re, itertools
20 import random
20 from cPickle import load, dump 21 from cPickle import load, dump
21 22
22 from zope.interface import implements 23 from zope.interface import implements
23 from twisted.python import log, runtime 24 from twisted.python import log, runtime
24 from twisted.persisted import styles 25 from twisted.persisted import styles
25 from buildbot.process import metrics 26 from buildbot.process import metrics
26 from buildbot import interfaces, util 27 from buildbot import interfaces, util
27 from buildbot.util.lru import SyncLRUCache 28 from buildbot.util.lru import SyncLRUCache
28 from buildbot.status.event import Event 29 from buildbot.status.event import Event
29 from buildbot.status.build import BuildStatus 30 from buildbot.status.build import BuildStatus
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 for build in self.generateFinishedBuilds(num_builds=1): 317 for build in self.generateFinishedBuilds(num_builds=1):
317 assert build and build.isFinished, \ 318 assert build and build.isFinished, \
318 'builder %s build %s is not finished' % ( 319 'builder %s build %s is not finished' % (
319 self.getName(), build) 320 self.getName(), build)
320 return build 321 return build
321 return None 322 return None
322 323
323 def getCategory(self): 324 def getCategory(self):
324 return self.category 325 return self.category
325 326
326 def getBuild(self, number): 327 def _resolveBuildNumber(self, number):
327 if number < 0: 328 if number < 0:
328 number = self.nextBuildNumber + number 329 number = self.nextBuildNumber + number
329 if number < 0 or number >= self.nextBuildNumber: 330 if number < 0 or number >= self.nextBuildNumber:
330 return None 331 return None
332 return number
331 333
334 def _safeGetBuild(self, number):
Isaac (away) 2013/07/02 02:38:25 maybe name this var 'build_number'
Mike Stip (use stip instead) 2013/07/02 05:43:53 Done.
332 try: 335 try:
333 return self.getBuildByNumber(number) 336 return self.getBuildByNumber(number)
334 except IndexError: 337 except IndexError:
335 return None 338 return None
336 339
340 def getBuild(self, number):
341 number = self._resolveBuildNumber(number)
342
343 if number is None:
344 return None
345
346 return self._safeGetBuild(number)
347
348 def getBuilds(self, numbers):
349 """Cache-aware method to get multiple builds.
350
351 Prevents cascading evict/load when multiple builds are requested in
352 succession: requesting build 1 evicts build 2, requesting build 2 evicts
353 build 3, etc.
354
355 We query the buildCache and load hits first, then misses. When loading,
356 we randomize the load order to alleviate the problem when external web
357 requests load builds sequentially (they don't have access to this
358 function).
359 """
360
361 numbers = list(enumerate(self._resolveBuildNumber(x) for x in numbers))
362 random.shuffle(numbers)
363
364 builds = [None] * len(numbers)
365 misses = []
366 for idx, number in numbers:
Isaac (away) 2013/07/02 02:38:25 better variable name for number, perhaps build_num
Mike Stip (use stip instead) 2013/07/02 05:43:53 Done.
367 if number is None:
368 continue
369 if number in self.buildCache.cache:
370 builds[idx] = self._safeGetBuild(number)
371 else:
372 misses.append((idx, number))
373
374 for idx, number in misses:
375 builds[idx] = self._safeGetBuild(number)
376
377 return builds
378
337 def getEvent(self, number): 379 def getEvent(self, number):
338 try: 380 try:
339 return self.events[number] 381 return self.events[number]
340 except IndexError: 382 except IndexError:
341 return None 383 return None
342 384
343 def generateFinishedBuilds(self, branches=[], 385 def generateFinishedBuilds(self, branches=[],
344 num_builds=None, 386 num_builds=None,
345 max_buildnum=None, 387 max_buildnum=None,
346 finished_before=None, 388 finished_before=None,
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 result['basedir'] = os.path.basename(self.basedir) 651 result['basedir'] = os.path.basename(self.basedir)
610 result['category'] = self.category 652 result['category'] = self.category
611 result['slaves'] = self.slavenames 653 result['slaves'] = self.slavenames
612 #result['url'] = self.parent.getURLForThing(self) 654 #result['url'] = self.parent.getURLForThing(self)
613 # TODO(maruel): Add cache settings? Do we care? 655 # TODO(maruel): Add cache settings? Do we care?
614 656
615 # Transient 657 # Transient
616 # Collect build numbers. 658 # Collect build numbers.
617 # Important: Only grab the *cached* builds numbers to reduce I/O. 659 # Important: Only grab the *cached* builds numbers to reduce I/O.
618 current_builds = [b.getNumber() for b in self.currentBuilds] 660 current_builds = [b.getNumber() for b in self.currentBuilds]
661
662 # Populates buildCache with last N builds.
663 buildnums = range(-1, -(self.buildCacheSize - 1), -1)
664 self.getBuilds(buildnums)
665
619 cached_builds = list(set(self.buildCache.cache.keys() + current_builds)) 666 cached_builds = list(set(self.buildCache.cache.keys() + current_builds))
620 cached_builds.sort() 667 cached_builds.sort()
621 result['cachedBuilds'] = cached_builds 668 result['cachedBuilds'] = cached_builds
622 result['currentBuilds'] = current_builds 669 result['currentBuilds'] = current_builds
623 result['state'] = self.getState()[0] 670 result['state'] = self.getState()[0]
624 # lies, but we don't have synchronous access to this info; use 671 # lies, but we don't have synchronous access to this info; use
625 # asDict_async instead 672 # asDict_async instead
626 result['pendingBuilds'] = 0 673 result['pendingBuilds'] = 0
627 return result 674 return result
628 675
629 def asDict_async(self): 676 def asDict_async(self):
630 """Just like L{asDict}, but with a nonzero pendingBuilds.""" 677 """Just like L{asDict}, but with a nonzero pendingBuilds."""
631 result = self.asDict() 678 result = self.asDict()
632 d = self.getPendingBuildRequestStatuses() 679 d = self.getPendingBuildRequestStatuses()
633 def combine(statuses): 680 def combine(statuses):
634 result['pendingBuilds'] = len(statuses) 681 result['pendingBuilds'] = len(statuses)
635 return result 682 return result
636 d.addCallback(combine) 683 d.addCallback(combine)
637 return d 684 return d
638 685
639 def getMetrics(self): 686 def getMetrics(self):
640 return self.botmaster.parent.metrics 687 return self.botmaster.parent.metrics
641 688
642 # vim: set ts=4 sts=4 sw=4 et: 689 # vim: set ts=4 sts=4 sw=4 et:
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698