Vinzenz Feenstra has uploaded a new change for review. Change subject: Improvement of the GuestAgent class memory usage ......................................................................
Improvement of the GuestAgent class memory usage Introduction of a new configuration option guest_agent_max_allowed_message_size which defines the maximum length of a message coming from the guest agent. The default value has been set to 1 MiB. Change in the implementation of reading and handling messages from the guest agent. Every 64KiB the newly arrived content is checked for a newline character and all messages are handled immediately before it continues to read. If the received data do not contain a new line character the data is appended to the buffer list and the _buffer_size variable increased by the size of all stored buffers in the list. If _buffer_size exceeds the defined threshold, defined in 'guest_agent_max_allowed_message_size', the buffer list will be discarded and _buffer_size will be reset to 0. If there is a started message which will be finished afterwards it will have an invalid format and therefore be discarded. This change has been done to improve the amount of memory consumed by instances of the GuestAgent class. Signed-off-by: Vinzenz Feenstra <[email protected]> Change-Id: Ibf6274bb10c9e3b80962b69c5df316f03ee21214 --- M vdsm/config.py.in M vdsm/guestIF.py 2 files changed, 39 insertions(+), 11 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/39/9239/1 diff --git a/vdsm/config.py.in b/vdsm/config.py.in index 8e7c6e8..fc35c71 100644 --- a/vdsm/config.py.in +++ b/vdsm/config.py.in @@ -89,6 +89,9 @@ 'Grace period (seconds) to let guest user close his ' 'applications before shutdown.'), + ('guest_agent_max_allowed_message_size', '1048576', + 'Maximum allowed size for guest agent messages.'), + ('guest_agent_timeout', '30', 'Time (in sec) to wait for guest agent.'), diff --git a/vdsm/guestIF.py b/vdsm/guestIF.py index 96c421b..1b188a4 100644 --- a/vdsm/guestIF.py +++ b/vdsm/guestIF.py @@ -23,6 +23,7 @@ import socket import json import supervdsm +from vdsm.config import config __RESTRICTED_CHARS = set(range(8 + 1)).union( set(range(0xB, 0xC + 1))).union( @@ -52,6 +53,8 @@ class GuestAgent (): def __init__(self, socketName, channelListener, log, user='Unknown', ips='', connect=True): + self.MAX_MESSAGE_SIZE = \ + config.getint('vars', 'guest_agent_max_allowed_message_size') self.log = log self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) # Save the socket's fileno because a call to fileno() fails if the @@ -95,7 +98,7 @@ self.log.debug("Attempting connection to %s", self._socketName) if self._sock.connect_ex(self._socketName) == 0: self.log.debug("Connected to %s", self._socketName) - self._buffer = '' + self._clear_read_buffer() self._forward('refresh') self._stopped = False ret = True @@ -259,23 +262,45 @@ self.log.log(logging.TRACE, "Guest connection timed out") self.guestStatus = None + def _clear_read_buffer(self): + self._buffer = [] + self._buffer_size = 0 + + def _process_message(self, line): + try: + (message, args) = self._parseLine(line) + self._agentTimestamp = time.time() + self._handleMessage(message, args) + except ValueError as err: + self.log.error("%s: %s" % (err, repr(line))) + + def _handle_data(self, data): + while '\n' in data: + line, data = data.split('\n', 1) + line = ''.join(self._buffer) + line + self._clear_read_buffer() + self._process_message(line) + + self._buffer.append(data) + self._buffer_size += len(data) + + if self._buffer_size >= self.MAX_MESSAGE_SIZE: + self.log.error("[GuestAgent._handle_data] Discarding buffer with " + "size: %d because the message reached maximum size " + "of %d bytes before message end was reached." % + (self._buffer_size, self.MAX_MESSAGE_SIZE)) + self._clear_read_buffer() + @staticmethod def _onChannelRead(self): try: - while True: - self._buffer += self._sock.recv(2 ** 16) + while (not self._stopped): + data = self._sock.recv(2 ** 16) + self._handle_data(data) except socket.error as err: if err.errno == 11: # Nothing more to receive (Resource temporarily unavailable). pass - while (not self._stopped) and (self._buffer.find('\n') >= 0): - line, self._buffer = self._buffer.split('\n', 1) - try: - (message, args) = self._parseLine(line) - self._agentTimestamp = time.time() - self._handleMessage(message, args) - except ValueError as err: - self.log.error("%s: %s" % (err, repr(line))) def _parseLine(self, line): args = json.loads(line.decode('utf8')) -- To view, visit http://gerrit.ovirt.org/9239 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ibf6274bb10c9e3b80962b69c5df316f03ee21214 Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Vinzenz Feenstra <[email protected]> _______________________________________________ vdsm-patches mailing list [email protected] https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches
