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

/historical/sqllog.py

https://bitbucket.org/lindenlab/apiary/
Python | 344 lines | 308 code | 11 blank | 25 comment | 9 complexity | db9152e15900ba1b4652261f4205f357 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. import heapq
  26. import re
  27. import sys
  28. from mergetools import imerge
  29. from timestamp import TimeStamp
  30. __all__ = [
  31. 'Event',
  32. 'CoalescedEvent',
  33. 'Sequence',
  34. 'parse_stanza',
  35. 'EventReader',
  36. 'input_events',
  37. 'FollowSequences',
  38. 'CoalesceSequences'
  39. ]
  40. headerRE = re.compile(r'^(\d+\.\d+)\t([\d.:]+)\t(\S+)\t(\w+)$')
  41. breakRE = re.compile(r'^\*{3,}$')
  42. class Event(object):
  43. # state values
  44. Query = 'QueryStart'
  45. Response = 'QueryResponse'
  46. End = 'Quit'
  47. def __init__(self, time, id, source, state, body):
  48. self.time = time
  49. if type(time) is not TimeStamp:
  50. self.time = TimeStamp(time)
  51. self.id = id
  52. self.source = source
  53. self.state = state
  54. self.body = body
  55. def __cmp__(self, other):
  56. c = cmp(self.time, other.time)
  57. if c == 0:
  58. if self.state == "Quit" and other.state != "Quit":
  59. return 1
  60. if self.state != "Quit" and other.state == "Quit":
  61. return -1
  62. return c
  63. def __str__(self):
  64. return ("%s\t%s\t%s\t%s\n%s\n**************************************\n"
  65. % (self.time, self.id, self.source, self.state, self.body))
  66. def events(self):
  67. es = []
  68. for event in self.body.split("\n+++\n"):
  69. parts = event.split(":", 1)
  70. if len(parts) == 2:
  71. (time, body) = parts
  72. status = Event.Query
  73. if body == "Quit":
  74. status = Event.End
  75. es.append(Event(time, self.id, self.source, status, body))
  76. return es
  77. class CoalescedEvent(Event):
  78. Sequence = 'Sequence'
  79. def __init__(self, shelf_life=None, max_life=None):
  80. self.time = None
  81. self.id = None
  82. self.source = None
  83. self.state = CoalescedEvent.Sequence
  84. self.body = ""
  85. self.ended = False
  86. self.lasttime = None
  87. self.staletime = None
  88. self.maxtime = None
  89. self.shelf_life = None
  90. if shelf_life:
  91. self.shelf_life = TimeStamp(shelf_life)
  92. self.max_life = None
  93. if max_life:
  94. self.max_life = TimeStamp(max_life)
  95. def add(self, event):
  96. if self.time is None:
  97. self.time = event.time
  98. if self.max_life:
  99. self.maxtime = self.time + self.max_life
  100. self.id = event.id
  101. self.source = event.source
  102. self.lasttime = event.time
  103. if self.shelf_life:
  104. self.staletime = self.lasttime + self.shelf_life
  105. if not event.state == Event.End:
  106. self.body += "%s:%s\n+++\n" % (event.time, event.body)
  107. else:
  108. self.body += "%s:Quit\n+++\n" % (event.time)
  109. self.ended = True
  110. def endIfNeeded(self):
  111. if not self.ended:
  112. self.add(Event(self.lasttime, self.id, self.source,
  113. Event.End, 'Quit'))
  114. def parse_stanza(input):
  115. match = None
  116. while not match:
  117. line = input.readline()
  118. if line == '': # empty string means EOF
  119. return None
  120. match = headerRE.match(line)
  121. (time, id, source, state) = match.groups()
  122. body = ''
  123. while True:
  124. line = input.readline()
  125. if line == '':
  126. break
  127. if breakRE.match(line):
  128. break
  129. body += line
  130. return Event(float(time), id, source, state, body)
  131. class Sequence(object):
  132. def __init__(self):
  133. self._count = 0
  134. self._time_start = None
  135. self._last_event = None
  136. def note(self, event):
  137. self._count += 1
  138. if self._time_start is None:
  139. self._time_start = event.time
  140. self._last_event = event
  141. def count(self):
  142. return self._count
  143. def time(self):
  144. return self._last_event.time - self._time_start
  145. def timeto(self, event):
  146. if self._last_event is None:
  147. return None
  148. return event.time - self._last_event.time
  149. def ended(self):
  150. return self._last_event.state == Event.End
  151. def generateEnd(self, t=None):
  152. e = self._last_event
  153. if t is None:
  154. t = e.time
  155. return Event(t, e.id, e.source, Event.End, "")
  156. class EventReader(object):
  157. def __init__(self, input):
  158. self._input = input
  159. def __iter__(self):
  160. while True:
  161. s = parse_stanza(self._input)
  162. if s is None:
  163. return
  164. if s.state == CoalescedEvent.Sequence:
  165. for t in s.events():
  166. yield t
  167. else:
  168. yield s
  169. def input_spec_to_file(spec):
  170. if spec == '-':
  171. return sys.stdin
  172. return file(spec)
  173. def input_events(specs):
  174. if len(specs) == 0:
  175. return iter(EventReader(sys.stdin))
  176. evs = map(EventReader, map(input_spec_to_file, specs))
  177. return imerge(*evs)
  178. class FollowSequences(object):
  179. def replay(self, events):
  180. connections = { }
  181. lastt = None;
  182. for e in events:
  183. id = e.id
  184. lastt = e.time
  185. if id not in connections:
  186. s = connections[id] = Sequence()
  187. self.addingSequence(s, e)
  188. else:
  189. s = connections[id]
  190. self.notingEvent(s, e)
  191. s.note(e)
  192. if s.ended():
  193. self.removingSequence(s, e)
  194. del connections[id]
  195. if False:
  196. expired = []
  197. for (id,s) in connections.iteritems():
  198. w = s.timeto(e)
  199. if w and float(w) > 60.0:
  200. expired.append((id,s))
  201. for (id,s) in expired:
  202. f = s.generateEnd(e.time)
  203. self.forcedEnd(s, f)
  204. self.removingSequence(s, f)
  205. del connections[id]
  206. for s in connections.itervalues():
  207. f = s.generateEnd(lastt)
  208. self.forcedEnd(s, f)
  209. self.removingSequence(s, f)
  210. def addingSequence(self, s, e):
  211. pass
  212. def notingEvent(self, s, e):
  213. pass
  214. def forcedEnd(self, s, e):
  215. pass
  216. def removingSequence(self, s, e):
  217. pass
  218. class CoalesceSequences(object):
  219. def __init__(self):
  220. self.connections = { }
  221. self.bytime = [ ]
  222. self.starttime = None
  223. self.lasttime = None
  224. def heartbeat(self, n):
  225. sys.stderr.write("%s: %d events... (%d connections, %d waiting)\n"
  226. % (str(self.lasttime - self.starttime), n, len(self.connections), len(self.bytime)))
  227. n = 0
  228. i = 0
  229. l = len(self.bytime)
  230. s = ""
  231. while n < 5 and i < l:
  232. en = 0
  233. while i < l and self.bytime[i].ended:
  234. en += 1
  235. i += 1
  236. if en > 0:
  237. s += " : --%d--" % en
  238. else:
  239. n += 1
  240. s += " : %s(%s)" % (self.bytime[i].id, str(self.lasttime - self.bytime[i].lasttime))
  241. i += 1
  242. sys.stderr.write(" ")
  243. sys.stderr.write(s)
  244. sys.stderr.write("\n")
  245. def age_out(self, c):
  246. if c.staletime and self.lasttime >= c.staletime:
  247. sys.stderr.write(" expiring %s, stale\n" % c.id)
  248. elif c.maxtime and self.lasttime >= c.maxtime:
  249. sys.stderr.write(" expiring %s, maxed out\n" % c.id)
  250. else:
  251. return False
  252. c.endIfNeeded()
  253. del self.connections[c.id]
  254. return True
  255. def flush_completed(self):
  256. bytime = self.bytime
  257. while bytime:
  258. c = bytime[0]
  259. if not c.ended:
  260. if not self.age_out(c):
  261. return
  262. heapq.heappop(bytime)
  263. self.fullSequence(c)
  264. # sys.stderr.write(" done %s\n" % c.id)
  265. def replay(self, events):
  266. n = 0;
  267. connections = self.connections
  268. bytime = self.bytime
  269. for e in events:
  270. id = e.id
  271. self.lasttime = e.time
  272. if self.starttime is None:
  273. self.starttime = self.lasttime
  274. n += 1
  275. if n % 10000 == 0:
  276. self.heartbeat(n)
  277. if id in connections:
  278. c = connections[id]
  279. self.age_out(c)
  280. if id not in connections:
  281. c = connections[id] = CoalescedEvent(30.0, 180.0)
  282. c.add(e)
  283. heapq.heappush(bytime, c)
  284. else:
  285. c.add(e)
  286. if e.state == Event.End:
  287. del connections[id]
  288. self.flush_completed()
  289. for d in connections.itervalues():
  290. d.endIfNeeded()
  291. self.flush_completed()
  292. def fullSequence(self, e):
  293. pass