Commit b18dd019 authored by Iustin Pop's avatar Iustin Pop
Browse files

http: use slicing instead of string modification

The combination of the current buffer splitting method and (4KB) buffer
size is very inefficient when writing big amounts of data. Just walking
over a 16 megabyte string using a 4K buffer takes (on a random computer)
1m06s, whereas using slices will decrease this to 0.080s, and slicing
with 32 KB size decreases this to 0.073s.

This means that uploading a big config file (it nears 1MB for big
clusters) will take more and more time per the number of nodes, since it
needs lots of slicing.

I happened upon this by accidentally setting all nodes as master
candidates, at which point just uploading the config file to all nodes
took 40s. Applying the patch decreases this to 15s (this probably can
still be optimized).

The patch also removes a duplicate constant (the one actually used is in
http/client.py), and changes the receive buffer size to use the same
constant.

Reviewed-by: imsnah
parent a3316e4a
......@@ -36,8 +36,6 @@ from ganeti import serializer
from ganeti import utils
HTTP_CLIENT_THREADS = 10
HTTP_GANETI_VERSION = "Ganeti %s" % constants.RELEASE_VERSION
HTTP_OK = 200
......@@ -71,6 +69,8 @@ _SSL_UNEXPECTED_EOF = "Unexpected EOF"
SOCKOP_RECV,
SOCKOP_SHUTDOWN) = range(3)
# send/receive quantum
SOCK_BUF_SIZE = 32768
class HttpError(Exception):
"""Internal exception for HTTP errors.
......@@ -469,17 +469,20 @@ class HttpMessageWriter(object):
buf = self._FormatMessage()
poller = select.poll()
while buf:
# Send only 4 KB at a time
data = buf[:4096]
pos = 0
end = len(buf)
while pos < end:
# Send only SOCK_BUF_SIZE bytes at a time
data = buf[pos:pos+SOCK_BUF_SIZE]
sent = SocketOperation(poller, sock, SOCKOP_SEND, data,
write_timeout)
# Remove sent bytes
buf = buf[sent:]
pos += sent
assert not buf, "Message wasn't sent completely"
assert pos == end, "Message wasn't sent completely"
def _PrepareMessage(self):
"""Prepares the HTTP message by setting mandatory headers.
......@@ -555,7 +558,7 @@ class HttpMessageReader(object):
buf = ""
eof = False
while self.parser_status != self.PS_COMPLETE:
data = SocketOperation(self.poller, sock, SOCKOP_RECV, 4096,
data = SocketOperation(self.poller, sock, SOCKOP_RECV, SOCK_BUF_SIZE,
read_timeout)
if data:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment