Mercurial > hg
comparison mercurial/keepalive.py @ 10282:08a0f04b56bd
many, many trivial check-code fixups
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 25 Jan 2010 00:05:27 -0600 |
parents | 430e59ff3437 |
children | 4612cded5176 |
comparison
equal
deleted
inserted
replaced
10281:e7d3b509af8b | 10282:08a0f04b56bd |
---|---|
118 import urllib2 | 118 import urllib2 |
119 | 119 |
120 DEBUG = None | 120 DEBUG = None |
121 | 121 |
122 import sys | 122 import sys |
123 if sys.version_info < (2, 4): HANDLE_ERRORS = 1 | 123 if sys.version_info < (2, 4): |
124 HANDLE_ERRORS = 1 | |
124 else: HANDLE_ERRORS = 0 | 125 else: HANDLE_ERRORS = 0 |
125 | 126 |
126 class ConnectionManager: | 127 class ConnectionManager: |
127 """ | 128 """ |
128 The connection manager must be able to: | 129 The connection manager must be able to: |
135 self._readymap = {} # map connection to ready state | 136 self._readymap = {} # map connection to ready state |
136 | 137 |
137 def add(self, host, connection, ready): | 138 def add(self, host, connection, ready): |
138 self._lock.acquire() | 139 self._lock.acquire() |
139 try: | 140 try: |
140 if not host in self._hostmap: self._hostmap[host] = [] | 141 if not host in self._hostmap: |
142 self._hostmap[host] = [] | |
141 self._hostmap[host].append(connection) | 143 self._hostmap[host].append(connection) |
142 self._connmap[connection] = host | 144 self._connmap[connection] = host |
143 self._readymap[connection] = ready | 145 self._readymap[connection] = ready |
144 finally: | 146 finally: |
145 self._lock.release() | 147 self._lock.release() |
158 if not self._hostmap[host]: del self._hostmap[host] | 160 if not self._hostmap[host]: del self._hostmap[host] |
159 finally: | 161 finally: |
160 self._lock.release() | 162 self._lock.release() |
161 | 163 |
162 def set_ready(self, connection, ready): | 164 def set_ready(self, connection, ready): |
163 try: self._readymap[connection] = ready | 165 try: |
164 except KeyError: pass | 166 self._readymap[connection] = ready |
167 except KeyError: | |
168 pass | |
165 | 169 |
166 def get_ready_conn(self, host): | 170 def get_ready_conn(self, host): |
167 conn = None | 171 conn = None |
168 self._lock.acquire() | 172 self._lock.acquire() |
169 try: | 173 try: |
212 """tells us that this request is now closed and the the | 216 """tells us that this request is now closed and the the |
213 connection is ready for another request""" | 217 connection is ready for another request""" |
214 self._cm.set_ready(connection, 1) | 218 self._cm.set_ready(connection, 1) |
215 | 219 |
216 def _remove_connection(self, host, connection, close=0): | 220 def _remove_connection(self, host, connection, close=0): |
217 if close: connection.close() | 221 if close: |
222 connection.close() | |
218 self._cm.remove(connection) | 223 self._cm.remove(connection) |
219 | 224 |
220 #### Transaction Execution | 225 #### Transaction Execution |
221 def http_open(self, req): | 226 def http_open(self, req): |
222 return self.do_open(HTTPConnection, req) | 227 return self.do_open(HTTPConnection, req) |
231 while h: | 236 while h: |
232 r = self._reuse_connection(h, req, host) | 237 r = self._reuse_connection(h, req, host) |
233 | 238 |
234 # if this response is non-None, then it worked and we're | 239 # if this response is non-None, then it worked and we're |
235 # done. Break out, skipping the else block. | 240 # done. Break out, skipping the else block. |
236 if r: break | 241 if r: |
242 break | |
237 | 243 |
238 # connection is bad - possibly closed by server | 244 # connection is bad - possibly closed by server |
239 # discard it and ask for the next free connection | 245 # discard it and ask for the next free connection |
240 h.close() | 246 h.close() |
241 self._cm.remove(h) | 247 self._cm.remove(h) |
242 h = self._cm.get_ready_conn(host) | 248 h = self._cm.get_ready_conn(host) |
243 else: | 249 else: |
244 # no (working) free connections were found. Create a new one. | 250 # no (working) free connections were found. Create a new one. |
245 h = http_class(host) | 251 h = http_class(host) |
246 if DEBUG: DEBUG.info("creating new connection to %s (%d)", | 252 if DEBUG: |
247 host, id(h)) | 253 DEBUG.info("creating new connection to %s (%d)", |
254 host, id(h)) | |
248 self._cm.add(host, h, 0) | 255 self._cm.add(host, h, 0) |
249 self._start_transaction(h, req) | 256 self._start_transaction(h, req) |
250 r = h.getresponse() | 257 r = h.getresponse() |
251 except (socket.error, httplib.HTTPException), err: | 258 except (socket.error, httplib.HTTPException), err: |
252 raise urllib2.URLError(err) | 259 raise urllib2.URLError(err) |
253 | 260 |
254 # if not a persistent connection, don't try to reuse it | 261 # if not a persistent connection, don't try to reuse it |
255 if r.will_close: self._cm.remove(h) | 262 if r.will_close: |
256 | 263 self._cm.remove(h) |
257 if DEBUG: DEBUG.info("STATUS: %s, %s", r.status, r.reason) | 264 |
265 if DEBUG: | |
266 DEBUG.info("STATUS: %s, %s", r.status, r.reason) | |
258 r._handler = self | 267 r._handler = self |
259 r._host = host | 268 r._host = host |
260 r._url = req.get_full_url() | 269 r._url = req.get_full_url() |
261 r._connection = h | 270 r._connection = h |
262 r.code = r.status | 271 r.code = r.status |
291 # where an exception was uncaught, and so the | 300 # where an exception was uncaught, and so the |
292 # connection stayed open. On the next try, the | 301 # connection stayed open. On the next try, the |
293 # same exception was raised, etc. The tradeoff is | 302 # same exception was raised, etc. The tradeoff is |
294 # that it's now possible this call will raise | 303 # that it's now possible this call will raise |
295 # a DIFFERENT exception | 304 # a DIFFERENT exception |
296 if DEBUG: DEBUG.error("unexpected exception - closing " + \ | 305 if DEBUG: |
297 "connection to %s (%d)", host, id(h)) | 306 DEBUG.error("unexpected exception - closing " |
307 "connection to %s (%d)", host, id(h)) | |
298 self._cm.remove(h) | 308 self._cm.remove(h) |
299 h.close() | 309 h.close() |
300 raise | 310 raise |
301 | 311 |
302 if r is None or r.version == 9: | 312 if r is None or r.version == 9: |
303 # httplib falls back to assuming HTTP 0.9 if it gets a | 313 # httplib falls back to assuming HTTP 0.9 if it gets a |
304 # bad header back. This is most likely to happen if | 314 # bad header back. This is most likely to happen if |
305 # the socket has been closed by the server since we | 315 # the socket has been closed by the server since we |
306 # last used the connection. | 316 # last used the connection. |
307 if DEBUG: DEBUG.info("failed to re-use connection to %s (%d)", | 317 if DEBUG: |
308 host, id(h)) | 318 DEBUG.info("failed to re-use connection to %s (%d)", |
319 host, id(h)) | |
309 r = None | 320 r = None |
310 else: | 321 else: |
311 if DEBUG: DEBUG.info("re-using connection to %s (%d)", host, id(h)) | 322 if DEBUG: |
323 DEBUG.info("re-using connection to %s (%d)", host, id(h)) | |
312 | 324 |
313 return r | 325 return r |
314 | 326 |
315 def _start_transaction(self, h, req): | 327 def _start_transaction(self, h, req): |
316 # What follows mostly reimplements HTTPConnection.request() | 328 # What follows mostly reimplements HTTPConnection.request() |
317 # except it adds self.parent.addheaders in the mix. | 329 # except it adds self.parent.addheaders in the mix. |
318 headers = req.headers.copy() | 330 headers = req.headers.copy() |
319 if sys.version_info >= (2, 4): | 331 if sys.version_info >= (2, 4): |
320 headers.update(req.unredirected_hdrs) | 332 headers.update(req.unredirected_hdrs) |
321 headers.update(self.parent.addheaders) | 333 headers.update(self.parent.addheaders) |
322 headers = dict((n.lower(), v) for n,v in headers.items()) | 334 headers = dict((n.lower(), v) for n, v in headers.items()) |
323 skipheaders = {} | 335 skipheaders = {} |
324 for n in ('host', 'accept-encoding'): | 336 for n in ('host', 'accept-encoding'): |
325 if n in headers: | 337 if n in headers: |
326 skipheaders['skip_' + n.replace('-', '_')] = 1 | 338 skipheaders['skip_' + n.replace('-', '_')] = 1 |
327 try: | 339 try: |
475 | 487 |
476 def readline(self, limit=-1): | 488 def readline(self, limit=-1): |
477 i = self._rbuf.find('\n') | 489 i = self._rbuf.find('\n') |
478 while i < 0 and not (0 < limit <= len(self._rbuf)): | 490 while i < 0 and not (0 < limit <= len(self._rbuf)): |
479 new = self._raw_read(self._rbufsize) | 491 new = self._raw_read(self._rbufsize) |
480 if not new: break | 492 if not new: |
493 break | |
481 i = new.find('\n') | 494 i = new.find('\n') |
482 if i >= 0: i = i + len(self._rbuf) | 495 if i >= 0: |
496 i = i + len(self._rbuf) | |
483 self._rbuf = self._rbuf + new | 497 self._rbuf = self._rbuf + new |
484 if i < 0: i = len(self._rbuf) | 498 if i < 0: |
485 else: i = i+1 | 499 i = len(self._rbuf) |
486 if 0 <= limit < len(self._rbuf): i = limit | 500 else: |
501 i = i + 1 | |
502 if 0 <= limit < len(self._rbuf): | |
503 i = limit | |
487 data, self._rbuf = self._rbuf[:i], self._rbuf[i:] | 504 data, self._rbuf = self._rbuf[:i], self._rbuf[i:] |
488 return data | 505 return data |
489 | 506 |
490 def readlines(self, sizehint = 0): | 507 def readlines(self, sizehint = 0): |
491 total = 0 | 508 total = 0 |
492 list = [] | 509 list = [] |
493 while 1: | 510 while 1: |
494 line = self.readline() | 511 line = self.readline() |
495 if not line: break | 512 if not line: |
513 break | |
496 list.append(line) | 514 list.append(line) |
497 total += len(line) | 515 total += len(line) |
498 if sizehint and total >= sizehint: | 516 if sizehint and total >= sizehint: |
499 break | 517 break |
500 return list | 518 return list |
526 # NOTE: we DO propagate the error, though, because we cannot simply | 544 # NOTE: we DO propagate the error, though, because we cannot simply |
527 # ignore the error... the caller will know if they can retry. | 545 # ignore the error... the caller will know if they can retry. |
528 if self.debuglevel > 0: | 546 if self.debuglevel > 0: |
529 print "send:", repr(str) | 547 print "send:", repr(str) |
530 try: | 548 try: |
531 blocksize=8192 | 549 blocksize = 8192 |
532 if hasattr(str,'read') : | 550 if hasattr(str,'read') : |
533 if self.debuglevel > 0: print "sendIng a read()able" | 551 if self.debuglevel > 0: |
552 print "sendIng a read()able" | |
534 data=str.read(blocksize) | 553 data=str.read(blocksize) |
535 while data: | 554 while data: |
536 self.sock.sendall(data) | 555 self.sock.sendall(data) |
537 data=str.read(blocksize) | 556 data=str.read(blocksize) |
538 else: | 557 else: |
586 HANDLE_ERRORS = i | 605 HANDLE_ERRORS = i |
587 try: | 606 try: |
588 fo = urllib2.urlopen(url) | 607 fo = urllib2.urlopen(url) |
589 fo.read() | 608 fo.read() |
590 fo.close() | 609 fo.close() |
591 try: status, reason = fo.status, fo.reason | 610 try: |
592 except AttributeError: status, reason = None, None | 611 status, reason = fo.status, fo.reason |
612 except AttributeError: | |
613 status, reason = None, None | |
593 except IOError, e: | 614 except IOError, e: |
594 print " EXCEPTION: %s" % e | 615 print " EXCEPTION: %s" % e |
595 raise | 616 raise |
596 else: | 617 else: |
597 print " status = %s, reason = %s" % (status, reason) | 618 print " status = %s, reason = %s" % (status, reason) |
633 | 654 |
634 fo = urllib2.urlopen(url) | 655 fo = urllib2.urlopen(url) |
635 foo = '' | 656 foo = '' |
636 while 1: | 657 while 1: |
637 f = fo.readline() | 658 f = fo.readline() |
638 if f: foo = foo + f | 659 if f: |
660 foo = foo + f | |
639 else: break | 661 else: break |
640 fo.close() | 662 fo.close() |
641 m = md5.new(foo) | 663 m = md5.new(foo) |
642 print format % ('keepalive readline', m.hexdigest()) | 664 print format % ('keepalive readline', m.hexdigest()) |
643 | 665 |
655 # now install the keepalive handler and try again | 677 # now install the keepalive handler and try again |
656 opener = urllib2.build_opener(HTTPHandler()) | 678 opener = urllib2.build_opener(HTTPHandler()) |
657 urllib2.install_opener(opener) | 679 urllib2.install_opener(opener) |
658 t2 = fetch(N, url) | 680 t2 = fetch(N, url) |
659 print ' TIME: %.3f s' % t2 | 681 print ' TIME: %.3f s' % t2 |
660 print ' improvement factor: %.2f' % (t1/t2, ) | 682 print ' improvement factor: %.2f' % (t1 / t2) |
661 | 683 |
662 def fetch(N, url, delay=0): | 684 def fetch(N, url, delay=0): |
663 import time | 685 import time |
664 lens = [] | 686 lens = [] |
665 starttime = time.time() | 687 starttime = time.time() |
666 for i in range(N): | 688 for i in range(N): |
667 if delay and i > 0: time.sleep(delay) | 689 if delay and i > 0: |
690 time.sleep(delay) | |
668 fo = urllib2.urlopen(url) | 691 fo = urllib2.urlopen(url) |
669 foo = fo.read() | 692 foo = fo.read() |
670 fo.close() | 693 fo.close() |
671 lens.append(len(foo)) | 694 lens.append(len(foo)) |
672 diff = time.time() - starttime | 695 diff = time.time() - starttime |
681 | 704 |
682 def test_timeout(url): | 705 def test_timeout(url): |
683 global DEBUG | 706 global DEBUG |
684 dbbackup = DEBUG | 707 dbbackup = DEBUG |
685 class FakeLogger: | 708 class FakeLogger: |
686 def debug(self, msg, *args): print msg % args | 709 def debug(self, msg, *args): |
710 print msg % args | |
687 info = warning = error = debug | 711 info = warning = error = debug |
688 DEBUG = FakeLogger() | 712 DEBUG = FakeLogger() |
689 print " fetching the file to establish a connection" | 713 print " fetching the file to establish a connection" |
690 fo = urllib2.urlopen(url) | 714 fo = urllib2.urlopen(url) |
691 data1 = fo.read() | 715 data1 = fo.read() |