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()