Package buildbot :: Package db :: Module schedulers
[frames] | no frames]

Source Code for Module buildbot.db.schedulers

  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 
  3  # License as published by the Free Software Foundation, version 2. 
  4  # 
  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 
  7  # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
  8  # details. 
  9  # 
 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 
 12  # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 13  # 
 14  # Copyright Buildbot Team Members 
 15   
 16  """ 
 17  Support for schedulers in the database 
 18  """ 
 19   
 20  from buildbot.util import json 
 21  import sqlalchemy as sa 
 22  import sqlalchemy.exc 
 23  from twisted.python import log 
 24  from buildbot.db import base 
 25   
26 -class SchedulersConnectorComponent(base.DBConnectorComponent):
27 """ 28 A DBConnectorComponent to handle maintaining schedulers' state in the db. 29 """ 30
31 - def getState(self, schedulerid):
32 """Get this scheduler's state, as a dictionary. Returs a Deferred""" 33 def thd(conn): 34 schedulers_tbl = self.db.model.schedulers 35 q = sa.select([ schedulers_tbl.c.state ], 36 whereclause=(schedulers_tbl.c.schedulerid == schedulerid)) 37 row = conn.execute(q).fetchone() 38 if not row: 39 return {} # really shouldn't happen - the row should exist 40 try: 41 return json.loads(row.state) 42 except: 43 log.msg("JSON error loading state for scheduler #%s" % (schedulerid,)) 44 return {}
45 return self.db.pool.do(thd)
46
47 - def setState(self, schedulerid, state):
48 """Set this scheduler's stored state, represented as a JSON-able 49 dictionary. Returs a Deferred. Note that this will overwrite any 50 existing state; be careful with updates!""" 51 def thd(conn): 52 schedulers_tbl = self.db.model.schedulers 53 q = schedulers_tbl.update( 54 whereclause=(schedulers_tbl.c.schedulerid == schedulerid)) 55 conn.execute(q, state=json.dumps(state))
56 return self.db.pool.do(thd) 57 58 # TODO: maybe only the singular is needed?
59 - def classifyChanges(self, schedulerid, classifications):
60 """Record a collection of classifications in the scheduler_changes 61 table. CLASSIFICATIONS is a dictionary mapping CHANGEID to IMPORTANT 62 (boolean). Returns a Deferred.""" 63 def thd(conn): 64 tbl = self.db.model.scheduler_changes 65 ins_q = tbl.insert() 66 upd_q = tbl.update( 67 ((tbl.c.schedulerid == schedulerid) 68 & (tbl.c.changeid == sa.bindparam('wc_changeid')))) 69 for changeid, important in classifications.items(): 70 # convert the 'important' value into an integer, since that 71 # is the column type 72 imp_int = important and 1 or 0 73 try: 74 conn.execute(ins_q, 75 schedulerid=schedulerid, 76 changeid=changeid, 77 important=imp_int) 78 except (sqlalchemy.exc.ProgrammingError, 79 sqlalchemy.exc.IntegrityError): 80 # insert failed, so try an update 81 conn.execute(upd_q, 82 wc_changeid=changeid, 83 important=imp_int)
84 85 return self.db.pool.do(thd) 86
87 - def flushChangeClassifications(self, schedulerid, less_than=None):
88 """ 89 Flush all scheduler_changes for L{schedulerid}, limiting to those less 90 than C{less_than} if the parameter is supplied. Returns a Deferred. 91 """ 92 def thd(conn): 93 scheduler_changes_tbl = self.db.model.scheduler_changes 94 wc = (scheduler_changes_tbl.c.schedulerid == schedulerid) 95 if less_than is not None: 96 wc = wc & (scheduler_changes_tbl.c.changeid < less_than) 97 q = scheduler_changes_tbl.delete(whereclause=wc) 98 conn.execute(q)
99 return self.db.pool.do(thd) 100
101 - class Thunk: pass
102 - def getChangeClassifications(self, schedulerid, branch=Thunk):
103 """ 104 Return the scheduler_changes rows for this scheduler, in the form of a 105 dictionary mapping changeid to a boolean (important). Returns a 106 Deferred. 107 108 @param schedulerid: scheduler to look up changes for 109 @type schedulerid: integer 110 111 @param branch: limit to changes with this branch 112 @type branch: string or None (for default branch) 113 114 @returns: dictionary via Deferred 115 """ 116 def thd(conn): 117 scheduler_changes_tbl = self.db.model.scheduler_changes 118 changes_tbl = self.db.model.changes 119 120 wc = (scheduler_changes_tbl.c.schedulerid == schedulerid) 121 if branch is not self.Thunk: 122 wc = wc & ( 123 (scheduler_changes_tbl.c.changeid == changes_tbl.c.changeid) & 124 (changes_tbl.c.branch == branch)) 125 q = sa.select( 126 [ scheduler_changes_tbl.c.changeid, scheduler_changes_tbl.c.important ], 127 whereclause=wc) 128 return dict([ (r.changeid, [False,True][r.important]) for r in conn.execute(q) ])
129 return self.db.pool.do(thd) 130
131 - def getSchedulerId(self, sched_name, sched_class):
132 """ 133 Get the schedulerid for the given scheduler, creating a new schedulerid 134 if none is found. 135 136 Note that this makes no attempt to "claim" the schedulerid: schedulers 137 with the same name and class, but running in different masters, will be 138 assigned the same schedulerid - with disastrous results. 139 140 @param sched_name: the scheduler's configured name 141 @param sched_class: the class name of this scheduler 142 @returns: schedulerid, via a Deferred 143 """ 144 def thd(conn): 145 # get a matching row, *or* one without a class_name (from 0.8.0) 146 schedulers_tbl = self.db.model.schedulers 147 q = schedulers_tbl.select( 148 whereclause=( 149 (schedulers_tbl.c.name == sched_name) & 150 ((schedulers_tbl.c.class_name == sched_class) | 151 (schedulers_tbl.c.class_name == '')))) 152 res = conn.execute(q) 153 row = res.fetchone() 154 res.close() 155 156 # if no existing row, then insert a new one and return it. There 157 # is no protection against races here, but that's OK - the worst 158 # that happens is two sourcestamps with identical content; before 159 # 0.8.4 this was always the case. 160 if not row: 161 q = schedulers_tbl.insert() 162 res = conn.execute(q, 163 name=sched_name, 164 class_name=sched_class, 165 state='{}') 166 return res.inserted_primary_key[0] 167 168 # upgrade the row with the class name, if necessary 169 if row.class_name == '': 170 q = schedulers_tbl.update( 171 whereclause=( 172 (schedulers_tbl.c.name == sched_name) & 173 (schedulers_tbl.c.class_name == ''))) 174 conn.execute(q, class_name=sched_class) 175 return row.schedulerid
176 return self.db.pool.do(thd) 177