PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/historical/hive_mysql.py

https://bitbucket.org/lindenlab/apiary/
Python | 246 lines | 216 code | 6 blank | 24 comment | 3 complexity | 65f144b8c0fabe5c03665b160a32549a MD5 | raw file
  1. #
  2. # $LicenseInfo:firstyear=2010&license=mit$
  3. #
  4. # Copyright (c) 2010, Linden Research, Inc.
  5. #
  6. # Permission is hereby granted, free of charge, to any person obtaining a copy
  7. # of this software and associated documentation files (the "Software"), to deal
  8. # in the Software without restriction, including without limitation the rights
  9. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. # copies of the Software, and to permit persons to whom the Software is
  11. # furnished to do so, subject to the following conditions:
  12. #
  13. # The above copyright notice and this permission notice shall be included in
  14. # all copies or substantial portions of the Software.
  15. #
  16. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. # THE SOFTWARE.
  23. # $/LicenseInfo$
  24. #
  25. from optparse import OptionParser
  26. import MySQLdb
  27. import re
  28. import time
  29. import hive
  30. import sqllog
  31. import timestamp
  32. def now(future=0.0):
  33. return timestamp.TimeStamp(time.time() + future)
  34. def wait_until(ts):
  35. tn = now()
  36. if ts > tn:
  37. delta = float(ts - tn)
  38. if delta > 65.0:
  39. raise Exception("trying to wait longer than 65s. now = %s, until = %s"
  40. % (str(tn), str(ts)))
  41. time.sleep(delta)
  42. mysql_host = 'localhost'
  43. mysql_port = 3306
  44. mysql_user = 'guest'
  45. mysql_passwd = ''
  46. mysql_db = 'test'
  47. class MySQLWorker(hive.Worker):
  48. def __init__(self, options, arguments):
  49. hive.Worker.__init__(self, options, arguments)
  50. self._asap = options.asap
  51. self._error = False
  52. self._errormsg = ''
  53. self._connect_options = {}
  54. self._connect_options['host'] = options.mysql_host
  55. self._connect_options['port'] = options.mysql_port
  56. self._connect_options['user'] = options.mysql_user
  57. self._connect_options['passwd'] = options.mysql_passwd
  58. self._connect_options['db'] = options.mysql_db
  59. self._connection = None
  60. def start(self):
  61. # self.log("starting")
  62. self._error = False
  63. self._errormsg = ''
  64. try:
  65. if self._connection is None:
  66. # self.log("making MySQL connection")
  67. connection = MySQLdb.connect(**self._connect_options)
  68. self._connection = connection
  69. pass
  70. except Exception, e: # more restrictive error catching?
  71. self._error = True
  72. self._errormsg = "500 " + str(e)
  73. def event(self, data):
  74. # self.log("event")
  75. if self._error:
  76. return
  77. try:
  78. (tstr, sql) = data.split("\t", 1)
  79. if not self._asap:
  80. self.log("waiting")
  81. wait_until(timestamp.TimeStamp(tstr))
  82. sql = sql.strip()
  83. if sql:
  84. self.log("executing SQL: " + sql)
  85. self.execute_sql(sql)
  86. # self.log("finished SQL")
  87. except Exception, e: # more restrictive error catching?
  88. self._error = True
  89. self._errormsg = "501 " + str(e)
  90. def end(self):
  91. # try:
  92. # self.log("committing")
  93. # self._connection.commit() # unclear if this should be here
  94. # except Exception, e:
  95. # pass
  96. try:
  97. if True:
  98. # self.log("closing")
  99. self._connection.close()
  100. self._connection = None
  101. except Exception, e:
  102. if not self._error:
  103. self._error = True
  104. self._errormsg = "502 " + str(e)
  105. # self.log("ended")
  106. if self._error:
  107. return self._errormsg
  108. return '200 OK'
  109. def execute_sql(self, sql):
  110. """Execute an SQL statement.
  111. Subclasses may override this to alter the SQL before being executed.
  112. If so, they should call this inherited version to actually execute
  113. the statement. It is acceptable for a sub-class to call this version
  114. multiple times.
  115. Exceptions are caught in the outer calling function (event())
  116. """
  117. cursor = self._connection.cursor()
  118. cursor.execute(sql)
  119. try:
  120. cursor.fetchall()
  121. except:
  122. pass # not all SQL has data to fetch
  123. cursor.close()
  124. class MySQLCentral(hive.Central):
  125. def __init__(self, options, arguments):
  126. hive.Central.__init__(self, options, arguments)
  127. self._events = sqllog.input_events(arguments)
  128. # this builds a sequence of events from the log streams in the
  129. # arguments, which come here from the command line
  130. self._connections = {}
  131. self._tally = {}
  132. self._time_offset = None
  133. self._tally_time = time.time() + 15.0
  134. def tally(self, msg):
  135. if "Duplicate entry" in msg:
  136. msg = '501 (1062, "Duplicate entry for key")'
  137. if "You have an error in your SQL syntax" in msg:
  138. msg = '501 (1064, "You have an error in your SQL syntax")'
  139. self._tally[msg] = self._tally.get(msg, 0) + 1
  140. if time.time() > self._tally_time:
  141. self.print_tally()
  142. def print_tally(self):
  143. keys = self._tally.keys()
  144. keys.sort()
  145. print
  146. print " count - message"
  147. print "------------ -------------------------------------------"
  148. for k in keys:
  149. print ("%12d - %s" % (self._tally[k], k))
  150. self._tally_time = time.time() + 15.0
  151. def next(self):
  152. try:
  153. while True:
  154. e = self._events.next() # e is a sqllog.Event object
  155. if e.state != sqllog.Event.Response:
  156. break
  157. except StopIteration:
  158. return False
  159. if self._time_offset is None:
  160. self._time_offset = now(1.0) - e.time
  161. t = self._time_offset + e.time
  162. id = e.id
  163. if e.state == sqllog.Event.End:
  164. if id in self._connections:
  165. self.tally("102 End connection")
  166. del self._connections[id]
  167. self.end(id)
  168. else:
  169. self.tally("103 Duplicate end")
  170. else:
  171. if id not in self._connections:
  172. self.tally("100 Start connection")
  173. s = self._connections[id] = True
  174. self.start(id)
  175. self.tally("101 Event")
  176. self.event(id, str(t) + "\t" + e.body)
  177. return True
  178. def result(self, seq, d):
  179. self.tally(d)
  180. def main(self):
  181. t = - time.time()
  182. c = - time.clock()
  183. hive.Central.main(self)
  184. c += time.clock()
  185. t += time.time()
  186. # This never actually happens because hive.Central.main(self) never completes.
  187. # Figure out how to force it to say it exited neatly?
  188. print ("Timing: %f process clock, %f wall clock" % (c, t))
  189. self.print_tally()
  190. class MySQLHive(hive.Hive):
  191. def __init__(self, central_cls=MySQLCentral, worker_cls=MySQLWorker):
  192. hive.Hive.__init__(self, central_cls, worker_cls)
  193. def add_options(self, parser):
  194. hive.Hive.add_options(self, parser)
  195. parser.add_option('--asap',
  196. action='store_true', default=False,
  197. help='run SQL connections as fast as possible (default: off)')
  198. parser.add_option('--mysql-host',
  199. default=mysql_host, metavar='HOST',
  200. help='MySQL server to connect to (default: %default)')
  201. parser.add_option('--mysql-port',
  202. default=mysql_port, metavar='PORT',
  203. help='MySQL port to connect on (default: %default)')
  204. parser.add_option('--mysql-user',
  205. default=mysql_user, metavar='USER',
  206. help='MySQL user to connect as (default: %default)')
  207. parser.add_option('--mysql-passwd',
  208. default=mysql_passwd, metavar='PW',
  209. help='MySQL password to connect with (default: %default)')
  210. parser.add_option('--mysql-db',
  211. default=mysql_db, metavar='DB',
  212. help='MySQL database to connect to (default: %default)')
  213. if __name__ == '__main__':
  214. MySQLHive().main()