Mercurial > hg
comparison mercurial/keepalive.py @ 40032:dc82ad1b7f77
keepalive: track request count and bytes sent
I want wire protocol interactions to report the number of
requests made and bytes transferred.
This commit teaches the very low-level custom HTTPConnection class
to track the number of bytes sent to the socket. This may vary from
the number of bytes that go on the wire due to e.g. TLS. That's OK.
KeepAliveHandler is taught to track the total number of requests
and total number of bytes sent across all requests.
Differential Revision: https://phab.mercurial-scm.org/D4856
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Mon, 01 Oct 2018 12:02:54 -0700 |
parents | f2dffa1359c6 |
children | 5e5b06087ec5 |
comparison
equal
deleted
inserted
replaced
40031:f2dffa1359c6 | 40032:dc82ad1b7f77 |
---|---|
172 return dict(self._hostmap) | 172 return dict(self._hostmap) |
173 | 173 |
174 class KeepAliveHandler(object): | 174 class KeepAliveHandler(object): |
175 def __init__(self): | 175 def __init__(self): |
176 self._cm = ConnectionManager() | 176 self._cm = ConnectionManager() |
177 self.requestscount = 0 | |
178 self.sentbytescount = 0 | |
177 | 179 |
178 #### Connection Management | 180 #### Connection Management |
179 def open_connections(self): | 181 def open_connections(self): |
180 """return a list of connected hosts and the number of connections | 182 """return a list of connected hosts and the number of connections |
181 to each. [('foo.com:80', 2), ('bar.org', 1)]""" | 183 to each. [('foo.com:80', 2), ('bar.org', 1)]""" |
310 DEBUG.info("re-using connection to %s (%d)", host, id(h)) | 312 DEBUG.info("re-using connection to %s (%d)", host, id(h)) |
311 | 313 |
312 return r | 314 return r |
313 | 315 |
314 def _start_transaction(self, h, req): | 316 def _start_transaction(self, h, req): |
317 oldbytescount = h.sentbytescount | |
318 | |
315 # What follows mostly reimplements HTTPConnection.request() | 319 # What follows mostly reimplements HTTPConnection.request() |
316 # except it adds self.parent.addheaders in the mix and sends headers | 320 # except it adds self.parent.addheaders in the mix and sends headers |
317 # in a deterministic order (to make testing easier). | 321 # in a deterministic order (to make testing easier). |
318 headers = util.sortdict(self.parent.addheaders) | 322 headers = util.sortdict(self.parent.addheaders) |
319 headers.update(sorted(req.headers.items())) | 323 headers.update(sorted(req.headers.items())) |
344 h.putheader(k, v) | 348 h.putheader(k, v) |
345 h.endheaders() | 349 h.endheaders() |
346 if urllibcompat.hasdata(req): | 350 if urllibcompat.hasdata(req): |
347 h.send(data) | 351 h.send(data) |
348 | 352 |
353 # This will fail to record events in case of I/O failure. That's OK. | |
354 self.requestscount += 1 | |
355 self.sentbytescount += h.sentbytescount - oldbytescount | |
356 | |
357 try: | |
358 self.parent.requestscount += 1 | |
359 self.parent.sentbytescount += h.sentbytescount - oldbytescount | |
360 except AttributeError: | |
361 pass | |
362 | |
349 class HTTPHandler(KeepAliveHandler, urlreq.httphandler): | 363 class HTTPHandler(KeepAliveHandler, urlreq.httphandler): |
350 pass | 364 pass |
351 | 365 |
352 class HTTPResponse(httplib.HTTPResponse): | 366 class HTTPResponse(httplib.HTTPResponse): |
353 # we need to subclass HTTPResponse in order to | 367 # we need to subclass HTTPResponse in order to |
583 if self.debuglevel > 0: | 597 if self.debuglevel > 0: |
584 print("sending a read()able") | 598 print("sending a read()able") |
585 data = read(blocksize) | 599 data = read(blocksize) |
586 while data: | 600 while data: |
587 self.sock.sendall(data) | 601 self.sock.sendall(data) |
602 self.sentbytescount += len(data) | |
588 data = read(blocksize) | 603 data = read(blocksize) |
589 else: | 604 else: |
590 self.sock.sendall(str) | 605 self.sock.sendall(str) |
606 self.sentbytescount += len(str) | |
591 except socket.error as v: | 607 except socket.error as v: |
592 reraise = True | 608 reraise = True |
593 if v[0] == errno.EPIPE: # Broken pipe | 609 if v[0] == errno.EPIPE: # Broken pipe |
594 if self._HTTPConnection__state == httplib._CS_REQ_SENT: | 610 if self._HTTPConnection__state == httplib._CS_REQ_SENT: |
595 self._broken_pipe_resp = None | 611 self._broken_pipe_resp = None |
622 # use the modified response class | 638 # use the modified response class |
623 response_class = HTTPResponse | 639 response_class = HTTPResponse |
624 send = safesend | 640 send = safesend |
625 getresponse = wrapgetresponse(httplib.HTTPConnection) | 641 getresponse = wrapgetresponse(httplib.HTTPConnection) |
626 | 642 |
643 def __init__(self, *args, **kwargs): | |
644 httplib.HTTPConnection.__init__(self, *args, **kwargs) | |
645 self.sentbytescount = 0 | |
627 | 646 |
628 ######################################################################### | 647 ######################################################################### |
629 ##### TEST FUNCTIONS | 648 ##### TEST FUNCTIONS |
630 ######################################################################### | 649 ######################################################################### |
631 | 650 |