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

Reply via email to