Changeset 709
- Timestamp:
- 09/05/08 17:04:04 (4 months ago)
- Files:
-
- buildbot/locks.py (modified) (4 diffs)
- buildbot/master.py (modified) (2 diffs)
- buildbot/process/base.py (modified) (4 diffs)
- buildbot/process/buildstep.py (modified) (4 diffs)
- buildbot/test/test_locks.py (modified) (4 diffs)
- docs/buildbot.texinfo (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
buildbot/locks.py
r708 r709 24 24 25 25 def __init__(self, name, maxCount=1): 26 self.name = name 27 self.waiting = [] 28 self.owners = [] 29 self.maxCount=maxCount 26 self.name = name # Name of the lock 27 self.waiting = [] # Current queue, tuples (LockAccess, deferred) 28 self.owners = [] # Current owners, tuples (owner, LockAccess) 29 self.maxCount=maxCount # maximal number of counting owners 30 30 31 31 def __repr__(self): 32 32 return self.description 33 33 34 def isAvailable(self): 34 def _getOwnersCount(self): 35 """ Return the number of current exclusive and counting owners. 36 37 @return: Tuple (number exclusive owners, number counting owners) 38 """ 39 num_excl, num_counting = 0, 0 40 for owner in self.owners: 41 if owner[1].mode == 'exclusive': 42 num_excl = num_excl + 1 43 else: # mode == 'counting' 44 num_counting = num_counting + 1 45 46 assert (num_excl == 1 and num_counting == 0) \ 47 or (num_excl == 0 and num_counting <= self.maxCount) 48 return num_excl, num_counting 49 50 51 def isAvailable(self, access): 35 52 """ Return a boolean whether the lock is available for claiming """ 36 debuglog("%s isAvailable: self.owners=%r" % (self, self.owners)) 37 return len(self.owners) < self.maxCount 38 39 def claim(self, owner): 53 debuglog("%s isAvailable(%s): self.owners=%r" 54 % (self, access, self.owners)) 55 num_excl, num_counting = self._getOwnersCount() 56 if access.mode == 'counting': 57 # Wants counting access 58 return num_excl == 0 and num_counting < self.maxCount 59 else: 60 # Wants exclusive access 61 return num_excl == 0 and num_counting == 0 62 63 def claim(self, owner, access): 40 64 """ Claim the lock (lock must be available) """ 41 debuglog("%s claim(%s )" % (self, owner))65 debuglog("%s claim(%s, %s)" % (self, owner, access.mode)) 42 66 assert owner is not None 43 assert len(self.owners) < self.maxCount, "ask for isAvailable() first" 44 self.owners.append(owner) 45 debuglog(" %s is claimed" % (self,)) 46 47 def release(self, owner): 67 assert self.isAvailable(access), "ask for isAvailable() first" 68 69 assert isinstance(access, LockAccess) 70 assert access.mode in ['counting', 'exclusive'] 71 self.owners.append((owner, access)) 72 debuglog(" %s is claimed '%s'" % (self, access.mode)) 73 74 def release(self, owner, access): 48 75 """ Release the lock """ 49 debuglog("%s release(%s)" % (self, owner)) 50 assert owner in self.owners 51 self.owners.remove(owner) 76 assert isinstance(access, LockAccess) 77 78 debuglog("%s release(%s, %s)" % (self, owner, access.mode)) 79 entry = (owner, access) 80 assert entry in self.owners 81 self.owners.remove(entry) 52 82 # who can we wake up? 53 if self.waiting: 54 d = self.waiting.pop(0) 83 # After an exclusive access, we may need to wake up several waiting. 84 # Break out of the loop when the first waiting client should not be awakened. 85 num_excl, num_counting = self._getOwnersCount() 86 while len(self.waiting) > 0: 87 access, d = self.waiting[0] 88 if access.mode == 'counting': 89 if num_excl > 0 or num_counting == self.maxCount: 90 break 91 else: 92 num_counting = num_counting + 1 93 else: 94 # access.mode == 'exclusive' 95 if num_excl > 0 or num_counting > 0: 96 break 97 else: 98 num_excl = num_excl + 1 99 100 del self.waiting[0] 55 101 reactor.callLater(0, d.callback, self) 56 102 57 def waitUntilMaybeAvailable(self, owner ):103 def waitUntilMaybeAvailable(self, owner, access): 58 104 """Fire when the lock *might* be available. The caller will need to 59 105 check with isAvailable() when the deferred fires. This loose form is … … 63 109 """ 64 110 debuglog("%s waitUntilAvailable(%s)" % (self, owner)) 65 if self.isAvailable(): 111 assert isinstance(access, LockAccess) 112 if self.isAvailable(access): 66 113 return defer.succeed(self) 67 114 d = defer.Deferred() 68 self.waiting.append( d)115 self.waiting.append((access, d)) 69 116 return d 70 117 … … 104 151 105 152 153 class LockAccess: 154 """ I am an object representing a way to access a lock. 155 156 @param lockid: LockId instance that should be accessed. 157 @type lockid: A MasterLock or SlaveLock instance. 158 159 @param mode: Mode of accessing the lock. 160 @type mode: A string, either 'counting' or 'exclusive'. 161 """ 162 def __init__(self, lockid, mode): 163 self.lockid = lockid 164 self.mode = mode 165 166 assert isinstance(lockid, (MasterLock, SlaveLock)) 167 assert mode in ['counting', 'exclusive'] 168 169 106 170 class BaseLockId(util.ComparableMixin): 107 171 """ Abstract base class for LockId classes. 108 172 173 Sets up the 'access()' function for the LockId's available to the user 174 (MasterLock and SlaveLock classes). 109 175 Derived classes should add 110 176 - Comparison with the L{util.ComparableMixin} via the L{compare_attrs} … … 113 179 class variable. 114 180 """ 181 def access(self, mode): 182 """ Express how the lock should be accessed """ 183 assert mode in ['counting', 'exclusive'] 184 return LockAccess(self, mode) 185 186 def defaultAccess(self): 187 """ For buildbot 0.7.7 compability: When user doesn't specify an access 188 mode, this one is chosen. 189 """ 190 return self.access('counting') 191 192 115 193 116 194 # master.cfg should only reference the following MasterLock and SlaveLock buildbot/master.py
r708 r709 642 642 for b in builders: 643 643 for l in b.get('locks', []): 644 if isinstance(l, locks.LockAccess): # User specified access to the lock 645 l = l.lockid 644 646 if lock_dict.has_key(l.name): 645 647 if lock_dict[l.name] is not l: … … 654 656 for s in b['factory'].steps: 655 657 for l in s[1].get('locks', []): 658 if isinstance(l, locks.LockAccess): # User specified access to the lock 659 l = l.lockid 656 660 if lock_dict.has_key(l.name): 657 661 if lock_dict[l.name] is not l: buildbot/process/base.py
r653 r709 8 8 from twisted.internet import reactor, defer, error 9 9 10 from buildbot import interfaces 10 from buildbot import interfaces, locks 11 11 from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, EXCEPTION 12 12 from buildbot.status.builder import Results, BuildRequestStatus … … 313 313 314 314 # convert all locks into their real forms 315 self.locks = [self.builder.botmaster.getLockByID(l) 316 for l in self.locks] 315 lock_list = [] 316 for access in self.locks: 317 if not isinstance(access, locks.LockAccess): 318 # Buildbot 0.7.7 compability: user did not specify access 319 access = access.defaultAccess() 320 lock = self.builder.botmaster.getLockByID(access.lockid) 321 lock_list.append((lock, access)) 322 self.locks = lock_list 317 323 # then narrow SlaveLocks down to the right slave 318 self.locks = [l.getLock(self.slavebuilder) for l in self.locks] 324 self.locks = [(l.getLock(self.slavebuilder), la) 325 for l, la in self.locks] 319 326 self.remote = slavebuilder.remote 320 327 self.remote.notifyOnDisconnect(self.lostRemote) … … 352 359 if not self.locks: 353 360 return defer.succeed(None) 354 for lock in self.locks:355 if not lock.isAvailable( ):361 for lock, access in self.locks: 362 if not lock.isAvailable(access): 356 363 log.msg("Build %s waiting for lock %s" % (self, lock)) 357 d = lock.waitUntilMaybeAvailable(self )364 d = lock.waitUntilMaybeAvailable(self, access) 358 365 d.addCallback(self.acquireLocks) 359 366 return d 360 367 # all locks are available, claim them all 361 for lock in self.locks:362 lock.claim(self )368 for lock, access in self.locks: 369 lock.claim(self, access) 363 370 return defer.succeed(None) 364 371 … … 585 592 def releaseLocks(self): 586 593 log.msg("releaseLocks(%s): %s" % (self, self.locks)) 587 for lock in self.locks:588 lock.release(self )594 for lock, access in self.locks: 595 lock.release(self, access) 589 596 590 597 # IBuildControl buildbot/process/buildstep.py
r677 r709 9 9 from twisted.web.util import formatFailure 10 10 11 from buildbot import interfaces 11 from buildbot import interfaces, locks 12 12 from buildbot.status import progress 13 13 from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, SKIPPED, \ … … 663 663 self.deferred = defer.Deferred() 664 664 # convert all locks into their real form 665 self.locks = [self.build.builder.botmaster.getLockByID(l) 666 for l in self.locks] 665 lock_list = [] 666 for access in self.locks: 667 if not isinstance(access, locks.LockAccess): 668 # Buildbot 0.7.7 compability: user did not specify access 669 access = access.defaultAccess() 670 lock = self.build.builder.botmaster.getLockByID(access.lockid) 671 lock_list.append((lock, access)) 672 self.locks = lock_list 667 673 # then narrow SlaveLocks down to the slave that this build is being 668 674 # run on 669 self.locks = [ l.getLock(self.build.slavebuilder) for lin self.locks]670 for l in self.locks:675 self.locks = [(l.getLock(self.build.slavebuilder), la) for l, la in self.locks] 676 for l, la in self.locks: 671 677 if l in self.build.locks: 672 678 log.msg("Hey, lock %s is claimed by both a Step (%s) and the" … … 681 687 if not self.locks: 682 688 return defer.succeed(None) 683 for lock in self.locks:684 if not lock.isAvailable( ):689 for lock, access in self.locks: 690 if not lock.isAvailable(access): 685 691 log.msg("step %s waiting for lock %s" % (self, lock)) 686 d = lock.waitUntilMaybeAvailable(self )692 d = lock.waitUntilMaybeAvailable(self, access) 687 693 d.addCallback(self.acquireLocks) 688 694 return d 689 695 # all locks are available, claim them all 690 for lock in self.locks:691 lock.claim(self )696 for lock, access in self.locks: 697 lock.claim(self, access) 692 698 return defer.succeed(None) 693 699 … … 770 776 def releaseLocks(self): 771 777 log.msg("releaseLocks(%s): %s" % (self, self.locks)) 772 for lock in self.locks:773 lock.release(self )778 for lock, access in self.locks: 779 lock.release(self, access) 774 780 775 781 def finished(self, results): buildbot/test/test_locks.py
r408 r709 13 13 from buildbot import locks 14 14 15 def claimHarder(lock, owner ):15 def claimHarder(lock, owner, la): 16 16 """Return a Deferred that will fire when the lock is claimed. Keep trying 17 17 until we succeed.""" 18 if lock.isAvailable( ):18 if lock.isAvailable(la): 19 19 #print "claimHarder(%s): claiming" % owner 20 lock.claim(owner )20 lock.claim(owner, la) 21 21 return defer.succeed(lock) 22 22 #print "claimHarder(%s): waiting" % owner 23 d = lock.waitUntilMaybeAvailable(owner )24 d.addCallback(claimHarder, owner )23 d = lock.waitUntilMaybeAvailable(owner, la) 24 d.addCallback(claimHarder, owner, la) 25 25 return d 26 26 27 def hold(lock, owner, mode="now"):27 def hold(lock, owner, la, mode="now"): 28 28 if mode == "now": 29 lock.release(owner )29 lock.release(owner, la) 30 30 elif mode == "very soon": 31 reactor.callLater(0, lock.release, owner )31 reactor.callLater(0, lock.release, owner, la) 32 32 elif mode == "soon": 33 reactor.callLater(0.1, lock.release, owner) 34 33 reactor.callLater(0.1, lock.release, owner, la) 35 34 36 35 class Unit(unittest.TestCase): 37 def testNow(self): 36 def testNowCounting(self): 37 lid = locks.MasterLock('dummy') 38 la = locks.LockAccess(lid, 'counting') 39 return self._testNow(la) 40 41 def testNowExclusive(self): 42 lid = locks.MasterLock('dummy') 43 la = locks.LockAccess(lid, 'exclusive') 44 return self._testNow(la) 45 46 def _testNow(self, la): 38 47 l = locks.BaseLock("name") 39 self.failUnless(l.isAvailable()) 40 l.claim("owner1") 41 self.failIf(l.isAvailable()) 42 l.release("owner1") 43 self.failUnless(l.isAvailable()) 44 45 def testLater(self): 48 self.failUnless(l.isAvailable(la)) 49 l.claim("owner1", la) 50 self.failIf(l.isAvailable(la)) 51 l.release("owner1", la) 52 self.failUnless(l.isAvailable(la)) 53 54 def testNowMixed1(self): 55 """ Test exclusive is not possible when a counting has the lock """ 56 lid = locks.MasterLock('dummy') 57 lac = locks.LockAccess(lid, 'counting') 58 lae = locks.LockAccess(lid, 'exclusive') 59 l = locks.BaseLock("name", maxCount=2) 60 self.failUnless(l.isAvailable(lac)) 61 l.claim("count-owner", lac) 62 self.failIf(l.isAvailable(lae)) 63 l.release("count-owner", lac) 64 self.failUnless(l.isAvailable(lac)) 65 66 def testNowMixed2(self): 67 """ Test counting is not possible when an exclsuive has the lock """ 68 lid = locks.MasterLock('dummy') 69 lac = locks.LockAccess(lid, 'counting') 70 lae = locks.LockAccess(lid, 'exclusive') 71 l = locks.BaseLock("name", maxCount=2) 72 self.failUnless(l.isAvailable(lae)) 73 l.claim("count-owner", lae) 74 self.failIf(l.isAvailable(lac)) 75 l.release("count-owner", lae) 76 self.failUnless(l.isAvailable(lae)) 77 78 def testLaterCounting(self): 79 lid = locks.MasterLock('dummy') 80 la = locks.LockAccess(lid, 'counting') 81 return self._testLater(la) 82 83 def testLaterExclusive(self): 84 lid = locks.MasterLock('dummy') 85 la = locks.LockAccess(lid, 'exclusive') 86 return self._testLater(la) 87 88 def _testLater(self, la): 46 89 lock = locks.BaseLock("name") 47 d = claimHarder(lock, "owner1") 48 d.addCallback(lambda lock: lock.release("owner1")) 49 return d 50 51 def testCompetition(self): 90 d = claimHarder(lock, "owner1", la) 91 d.addCallback(lambda lock: lock.release("owner1", la)) 92 return d 93 94 def testCompetitionCounting(self): 95 lid = locks.MasterLock('dummy') 96 la = locks.LockAccess(lid, 'counting') 97 return self._testCompetition(la) 98 99 def testCompetitionExclusive(self): 100 lid = locks.MasterLock('dummy') 101 la = locks.LockAccess(lid, 'exclusive') 102 return self._testCompetition(la) 103 104 def _testCompetition(self, la): 52 105 lock = locks.BaseLock("name") 53 d = claimHarder(lock, "owner1" )54 d.addCallback(self._claim1 )55 return d 56 def _claim1(self, lock ):106 d = claimHarder(lock, "owner1", la) 107 d.addCallback(self._claim1, la) 108 return d 109 def _claim1(self, lock, la): 57 110 # we should have claimed it by now 58 self.failIf(lock.isAvailable( ))111 self.failIf(lock.isAvailable(la)) 59 112 # now set up two competing owners. We don't know which will get the 60 113 # lock first. 61 d2 = claimHarder(lock, "owner2" )62 d2.addCallback(hold, "owner2", "now")63 d3 = claimHarder(lock, "owner3" )64 d3.addCallback(hold, "owner3", "soon")114 d2 = claimHarder(lock, "owner2", la) 115 d2.addCallback(hold, "owner2", la, "now") 116 d3 = claimHarder(lock, "owner3", la) 117 d3.addCallback(hold, "owner3", la, "soon") 65 118 dl = defer.DeferredList([d2,d3]) 66 dl.addCallback(self._cleanup, lock )119 dl.addCallback(self._cleanup, lock, la) 67 120 # and release the lock in a moment 68 reactor.callLater(0.1, lock.release, "owner1" )121 reactor.callLater(0.1, lock.release, "owner1", la) 69 122 return dl 70 123 71 def _cleanup(self, res, lock): 72 d = claimHarder(lock, "cleanup") 73 d.addCallback(lambda lock: lock.release("cleanup")) 74 return d 75 76 def testRandom(self): 124 def _cleanup(self, res, lock, la): 125 d = claimHarder(lock, "cleanup", la) 126 d.addCallback(lambda lock: lock.release("cleanup", la)) 127 return d 128 129 def testRandomCounting(self): 130 lid = locks.MasterLock('dummy') 131 la = locks.LockAccess(lid, 'counting') 132 return self._testRandom(la) 133 134 def testRandomExclusive(self): 135 lid = locks.MasterLock('dummy') 136 la = locks.LockAccess(lid, 'exclusive') 137 return self._testRandom(la) 138 139 def _testRandom(self, la): 77 140 lock = locks.BaseLock("name") 78 141 dl = [] … … 80 143 owner = "owner%d" % i 81 144 mode = random.choice(["now", "very soon", "soon"]) 82 d = claimHarder(lock, owner )83 d.addCallback(hold, owner, mode)145 d = claimHarder(lock, owner, la) 146 d.addCallback(hold, owner, la, mode) 84 147 dl.append(d) 85 148 d = defer.DeferredList(dl) 86 d.addCallback(self._cleanup, lock )149 d.addCallback(self._cleanup, lock, la) 87 150 return d 88 151 89 152 class Multi(unittest.TestCase): 90 def testNow(self): 153 def testNowCounting(self): 154 lid = locks.MasterLock('dummy') 155 la = locks.LockAccess(lid, 'counting') 91 156 lock = locks.BaseLock("name", 2) 92 self.failUnless(lock.isAvailable()) 93 lock.claim("owner1") 94 self.failUnless(lock.isAvailable()) 95 lock.claim("owner2") 96 self.failIf(lock.isAvailable()) 97 lock.release("owner1") 98 self.failUnless(lock.isAvailable()) 99 lock.release("owner2") 100 self.failUnless(lock.isAvailable()) 101 102 def testLater(self): 157 self.failUnless(lock.isAvailable(la)) 158 lock.claim("owner1", la) 159 self.failUnless(lock.isAvailable(la)) 160 lock.claim("owner2", la) 161 self.failIf(lock.isAvailable(la)) 162 lock.release("owner1", la) 163 self.failUnless(lock.isAvailable(la)) 164 lock.release("owner2", la) 165 self.failUnless(lock.isAvailable(la)) 166 167 def testLaterCounting(self): 168 lid = locks.MasterLock('dummy') 169 la = locks.LockAccess(lid, 'counting') 103 170 lock = locks.BaseLock("name", 2) 104 lock.claim("owner1" )105 lock.claim("owner2" )106 d = claimHarder(lock, "owner3" )107 d.addCallback(lambda lock: lock.release("owner3" ))108 lock.release("owner2" )109 lock.release("owner1" )110 return d 111 112 def _cleanup(self, res, lock, count ):171 lock.claim("owner1", la) 172 lock.claim("owner2", la) 173 d = claimHarder(lock, "owner3", la) 174 d.addCallback(lambda lock: lock.release("owner3", la)) 175 lock.release("owner2", la) 176 lock.release("owner1", la) 177 return d 178 179 def _cleanup(self, res, lock, count, la): 113 180 dl = [] 114 181 for i in range(count): 115 d = claimHarder(lock, "cleanup%d" % i )182 d = claimHarder(lock, "cleanup%d" % i, la) 116 183 dl.append(d) 117 184 d2 = defer.DeferredList(dl) … … 120 187 def _release(res): 121 188 for i in range(count): 122 lock.release("cleanup%d" % i )189 lock.release("cleanup%d" % i, la) 123 190 d2.addCallback(_release) 124 191 return d2 125 192 126 def testRandom(self): 193 def testRandomCounting(self): 194 lid = locks.MasterLock('dummy') 195 la = locks.LockAccess(lid, 'counting') 127 196 COUNT = 5 128 197 lock = locks.BaseLock("name", COUNT) … … 131 200 owner = "owner%d" % i 132 201 mode = random.choice(["now", "very soon", "soon"]) 133 d = claimHarder(lock, owner )202 d = claimHarder(lock, owner, la) 134 203 def _check(lock): 135 204 self.failIf(len(lock.owners) > COUNT) 136 205 return lock 137 206 d.addCallback(_check) 138 d.addCallback(hold, owner, mode)207 d.addCallback(hold, owner, la, mode) 139 208 dl.append(d) 140 209 d = defer.DeferredList(dl) 141 d.addCallback(self._cleanup, lock, COUNT )210 d.addCallback(self._cleanup, lock, COUNT, la) 142 211 return d 143 212 docs/buildbot.texinfo
r708 r709 5787 5787 @slindex buildbot.locks.MasterLock 5788 5788 @slindex buildbot.locks.SlaveLock 5789 @slindex buildbot.locks.LockAccess 5789 5790 5790 5791 For various reasons, you may want to prevent certain Steps (or perhaps … … 5806 5807 simultaneous builds as there are machines. 5807 5808 5809 When using a @code{Lock}, you can specify how you want to access it 5810 with a @code{LockAccess} object. You can have an exclusive lock (the 5811 @code{'exclusive'} mode) where the lock has exactly one owner, or 5812 share it with with others up to the limit (the @code{'counting'} 5813 mode). 5814 5808 5815 Each @code{Lock} is created with a unique name. Each lock gets a count 5809 of how many owners it may have : how many processes can claim it at the5816 of how many owners it may have in @code{'counting'} mode: how many processes can claim it at the 5810 5817 same time. This limit defaults to one, and is controllable through the 5811 5818 @code{maxCount} argument. On @code{SlaveLock}s you can set the owner … … 5815 5822 @code{maxCountForSlave} get their owner count from @code{maxCount}. 5816 5823 5817 To use a lock, simply include it in the @code{locks=} argument of the5824 To use a lock, simply include it with the desired mode of access in the @code{locks=} argument of the 5818 5825 @code{BuildStep} object that should obtain the lock before it runs. 5819 This argument accepts a list of @code{Lock} objects: the Step will 5820 acquire all of them before it runs. 5826 This argument accepts a list of @code{LockAccess} objects: the Step will 5827 acquire all of them before it runs. (For backwards compatibility, the 5828 list also accepts @code{Lock} objects which are accessed in 5829 @code{'counting'} mode.) 5821 5830 5822 5831 To claim a lock for the whole Build, add a @code{'locks'} key to the 5823 builder specification dictionary with the same list of @code{Lock} 5824 objects. (This is the dictionary that has the @code{'name'}, 5832 builder specification dictionary with the same list of 5833 @code{LockAccess} objects (and for backwards compatibility, the list 5834 also accepts @code{Lock} objects which are accessed in 5835 @code{'counting'} mode). 5836 (The builder specification dictionary is the dictionary that has the @code{'name'}, 5825 5837 @code{'slavename'}, @code{'builddir'}, and @code{'factory'} keys). The 5826 5838 @code{Build} object also accepts a @code{locks=} argument, but unless … … 5856 5868 f.addStep(source.SVN(svnurl="http://example.org/svn/Trunk")) 5857 5869 f.addStep(shell.ShellCommand(command="make all")) 5858 f.addStep(shell.ShellCommand(command="make test", locks=[db_lock])) 5870 f.addStep(shell.ShellCommand(command="make test", 5871 locks=[db_lock.access('exclusive')])) 5859 5872 b1 = @{'name': 'full1', 'slavename': 'bot-1', 'builddir': 'f1', 'factory': f@} 5860 5873 b2 = @{'name': 'full2', 'slavename': 'bot-2', 'builddir': 'f2', 'factory': f@} … … 5862 5875 c['builders'] = [b1, b2, b3] 5863 5876 @end example 5877 5878 Note that by default, a @code{Lock} uses a @code{maxCount=1} limit, so 5879 you can also use the @code{'counting'} access mode in this example. 5864 5880 5865 5881 In the next example, we have one buildslave hosting three separate … … 5887 5903 f24 = factory.Trial(source, trialpython=["python2.4"]) 5888 5904 b1 = @{'name': 'p22', 'slavename': 'bot-1', 'builddir': 'p22', 5889 'factory': f22, 'locks': [slow_lock ] @}5905 'factory': f22, 'locks': [slow_lock.access('counting')] @} 5890 5906 b2 = @{'name': 'p23', 'slavename': 'bot-1', 'builddir': 'p23', 5891 'factory': f23, 'locks': [slow_lock ] @}5907 'factory': f23, 'locks': [slow_lock.access('counting')] @} 5892 5908 b3 = @{'name': 'p24', 'slavename': 'bot-1', 'builddir': 'p24', 5893 'factory': f24, 'locks': [slow_lock ] @}5909 'factory': f24, 'locks': [slow_lock.access('counting')] @} 5894 5910 c['builders'] = [b1, b2, b3] 5911 @end example 5912 5913 You can also mix access modes. In the next example, a limit of at most 5914 two builds is enforced. The cleanup process however needs exclusive 5915 access to prevent interference with the build processes. 5916 5917 @example 5918 from buildbot import locks 5919 from buildbot.steps import source, shell 5920 from buildbot.process import factory 5921 5922 build_lock = locks.MasterLock("builds", maxCount=2) 5923 fb = factory.BuildFactory() 5924 fb.addStep(source.SVN(svnurl="http://example.org/svn/Trunk")) 5925 fb.addStep(shell.ShellCommand(command=["make", "all"])) 5926 b1 = @{'name': 'b1', 'slavename': 'bot-1', 'builddir' : 'b1', 5927 'factory': fb, 'locks': [build_lock.access('counting')] @} 5928 b2 = @{'name': 'b2', 'slavename': 'bot-2', 'builddir' : 'b2', 5929 'factory': fb, 'locks': [build_lock.access('counting')] @} 5930 b3 = @{'name': 'b3', 'slavename': 'bot-3', 'builddir' : 'b3', 5931 'factory': fb, 'locks': [build_lock.access('counting')] @} 5932 fc = factory.BuildFactory() 5933 fc.addStep(shell.ShellCommand(command=["cleanup"])) 5934 cl = @{'name': 'clean', 'slavename': 'bot-1', 'builddir' :clean', 5935 'factory': fc, 'locks': [build_lock.access('exclusive')] @} 5936 c['builders'] = [b1, b2, b3, cl] 5895 5937 @end example 5896 5938 … … 5915 5957 f = factory.BuildFactory() 5916 5958 f.addStep(source.SVN(svnurl="http://example.org/svn/Trunk")) 5917 f.addStep(shell.ShellCommand(command="make all", locks=[cpu_lock])) 5918 f.addStep(shell.ShellCommand(command="make test", locks=[cpu_lock])) 5919 f.addStep(shell.ShellCommand(command="make db-test", locks=[db_lock, cpu_lock])) 5959 f.addStep(shell.ShellCommand(command="make all", 5960 locks=[cpu_lock.access('counting')])) 5961 f.addStep(shell.ShellCommand(command="make test", 5962 locks=[cpu_lock.access('counting')])) 5963 f.addStep(shell.ShellCommand(command="make db-test", 5964 locks=[db_lock.access('exclusive'), 5965 cpu_lock.access('counting')])) 5920 5966 5921 5967 b1 = @{'name': 'full1', 'slavename': 'bot-slow', 'builddir': 'full1',
![[Buildbot Logo]](/trac/chrome/site/header-text-transparent.png)