| 1129 | @testing.requires.threading_with_mock |
| 1130 | @testing.requires.timing_intensive |
| 1131 | def test_timeout_race(self): |
| 1132 | # test a race condition where the initial connecting threads all race |
| 1133 | # to queue.Empty, then block on the mutex. each thread consumes a |
| 1134 | # connection as they go in. when the limit is reached, the remaining |
| 1135 | # threads go in, and get TimeoutError; even though they never got to |
| 1136 | # wait for the timeout on queue.get(). the fix involves checking the |
| 1137 | # timeout again within the mutex, and if so, unlocking and throwing |
| 1138 | # them back to the start of do_get() |
| 1139 | dbapi = MockDBAPI() |
| 1140 | p = pool.QueuePool( |
| 1141 | creator=lambda: dbapi.connect(delay=0.05), |
| 1142 | pool_size=2, |
| 1143 | max_overflow=1, |
| 1144 | timeout=3, |
| 1145 | ) |
| 1146 | timeouts = [] |
| 1147 | |
| 1148 | def checkout(): |
| 1149 | barrier.wait() |
| 1150 | for x in range(1): |
| 1151 | now = time.time() |
| 1152 | try: |
| 1153 | c1 = p.connect() |
| 1154 | except tsa.exc.TimeoutError: |
| 1155 | timeouts.append(time.time() - now) |
| 1156 | continue |
| 1157 | time.sleep(4) |
| 1158 | c1.close() |
| 1159 | |
| 1160 | barrier = threading.Barrier(10) |
| 1161 | threads = [] |
| 1162 | for i in range(10): |
| 1163 | th = threading.Thread(target=checkout) |
| 1164 | th.start() |
| 1165 | threads.append(th) |
| 1166 | for th in threads: |
| 1167 | th.join(join_timeout) |
| 1168 | |
| 1169 | assert len(timeouts) > 0 |
| 1170 | for t in timeouts: |
| 1171 | assert t >= 3, "Not all timeouts were >= 3 seconds %r" % timeouts |
| 1172 | # normally, the timeout should under 4 seconds, |
| 1173 | # but on a loaded down buildbot it can go up. |
| 1174 | assert t < 14, "Not all timeouts were < 14 seconds %r" % timeouts |
| 1175 | |
| 1176 | def _test_overflow(self, thread_count, max_overflow): |
| 1177 | reaper = testing.engines.ConnectionKiller() |