PageRenderTime 152ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/historical/sqllog_gentest.py

https://bitbucket.org/lindenlab/apiary/
Python | 196 lines | 166 code | 6 blank | 24 comment | 0 complexity | 9d3cb197c7c3715698b1b3b80b5cc403 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 math
  26. import random
  27. import sys
  28. import sqllog
  29. import timestamp
  30. class SQLModel(object):
  31. def __init__(self):
  32. self._sum_of_weights = 0.0
  33. self._entries = []
  34. self._weights = []
  35. self._accounts = []
  36. self._add_all_sql_options()
  37. def initial_sql(self):
  38. sql = """
  39. DROP TABLE IF EXISTS `test`.`bankbalance`;
  40. DROP TABLE IF EXISTS `test`.`banktransaction`;
  41. CREATE TABLE `test`.`bankbalance` (
  42. `acct` VARCHAR(16) NOT NULL,
  43. `balance` INT NOT NULL DEFAULT 0,
  44. PRIMARY KEY (`acct`)
  45. );
  46. CREATE TABLE `test`.`banktransaction` (
  47. `sequence` INT NOT NULL AUTO_INCREMENT,
  48. `acct` VARCHAR(16) NOT NULL,
  49. `amount` INT NOT NULL DEFAULT 0,
  50. `cleared` ENUM('N', 'Y') DEFAULT 'N',
  51. PRIMARY KEY (`sequence`),
  52. INDEX acct(`acct`)
  53. );
  54. INSERT INTO bankbalance SET acct="zzz-99999", balance=0;
  55. """
  56. return sql.split(';')
  57. def _add_sql_option(self, weight, sql):
  58. self._sum_of_weights += weight
  59. self._entries.append(sql)
  60. self._weights.append(weight)
  61. def _add_all_sql_options(self):
  62. options = """
  63. 2:INSERT INTO bankbalance SET acct="%(newacct)s", balance=100
  64. 25:INSERT INTO banktransaction SET acct="%(acct)s", amount=%(delta)d
  65. 5:SELECT acct FROM bankbalance WHERE balance < 0
  66. 30:SELECT balance FROM bankbalance WHERE acct="%(acct)s"
  67. 5:UPDATE bankbalance SET balance=balance+%(delta)d WHERE acct="%(acct)s"
  68. 5:SELECT sequence, amount FROM banktransaction WHERE acct="%(acct)s" AND cleared="N"
  69. 5:UPDATE banktransaction SET cleared="Y" WHERE acct="%(acct)s" AND cleared="N"
  70. """
  71. for line in options.split('\n'):
  72. if ':' in line:
  73. (weight,sql) = line.split(':',1)
  74. weight = float(weight)
  75. self._add_sql_option(weight,sql)
  76. def _random_acct(self):
  77. if self._accounts:
  78. return random.choice(self._accounts)
  79. return 'zzz-99999'
  80. def _random_new_acct(self):
  81. acct = 'aaa-%05d' % random.randint(0,99999)
  82. self._accounts.append(acct)
  83. return acct
  84. def _random_delta(self):
  85. return random.randint(-20,20)
  86. def random_sql(self):
  87. v = random.uniform(0.0, self._sum_of_weights)
  88. for i in xrange(0, len(self._entries)):
  89. v -= self._weights[i]
  90. if v < 0.0:
  91. sql = self._entries[i]
  92. break
  93. values = {}
  94. if '%(newacct)' in sql:
  95. values['newacct'] = self._random_new_acct()
  96. if '%(acct)' in sql:
  97. values['acct'] = self._random_acct()
  98. if '%(delta)' in sql:
  99. values['delta'] = self._random_delta()
  100. return sql % values
  101. class Generator(object):
  102. def __init__(self, model, target_event_count,
  103. target_concurrency, target_sequence_length):
  104. self._model = model
  105. self._target_event_count = target_event_count
  106. self._target_concurrency = target_concurrency
  107. self._target_sequence_length = target_sequence_length
  108. def run(self):
  109. self._sequences = []
  110. self._sequence_count = 0
  111. self._sequence_events_to_go = { }
  112. self._event_count = 0
  113. self._time = timestamp.TimeStamp(1000000)
  114. self._timeincr = timestamp.TimeStamp(0,1000) # 10ms
  115. self.initial();
  116. while self.step():
  117. pass
  118. def initial(self):
  119. name = "7:999999"
  120. start = self._time
  121. for sql in self._model.initial_sql():
  122. sql = sql.strip()
  123. if sql:
  124. self.output_event(name, "Init", sql)
  125. self.gen_end(name)
  126. self._time = start + timestamp.TimeStamp(1)
  127. def step(self):
  128. winding_down = self._event_count > self._target_event_count
  129. how_full = float(len(self._sequences)) / self._target_concurrency
  130. should_add = math.exp(-1.0 * math.pow(how_full, 2.0))
  131. if not winding_down and random.random() < should_add:
  132. self.step_add()
  133. return True
  134. if self._sequences:
  135. self.step_event(random.choice(self._sequences))
  136. return True
  137. return False # nothing to do!
  138. def step_add(self):
  139. self._sequence_count += 1
  140. name = "8:%06d" % self._sequence_count
  141. count = max(1, int(random.normalvariate(
  142. self._target_sequence_length,
  143. self._target_sequence_length/2.0)))
  144. self._sequences.append(name)
  145. self._sequence_events_to_go[name] = count
  146. self.step_event(name)
  147. def step_event(self, name):
  148. if self._sequence_events_to_go[name] > 0:
  149. self.gen_event(name)
  150. self._sequence_events_to_go[name] -= 1
  151. self._event_count += 1
  152. else:
  153. self.gen_end(name)
  154. del self._sequence_events_to_go[name]
  155. self._sequences = self._sequence_events_to_go.keys()
  156. def gen_event(self, name):
  157. self.output_event(name, sqllog.Event.Query, self._model.random_sql())
  158. def gen_end(self, name):
  159. self.output_event(name, sqllog.Event.End, "Quit")
  160. def output_event(self, seq, state, body):
  161. t = self._time
  162. self._time = self._time + self._timeincr
  163. e = sqllog.Event(t, seq, "test", state, body)
  164. sys.stdout.write(str(e))
  165. if __name__ == '__main__':
  166. m = SQLModel()
  167. g = Generator(m, 1000, 5, 6.0)
  168. g.run()