Send messages as Strings
authorKlaus Aehlig <aehlig@google.com>
Mon, 30 Nov 2015 14:19:38 +0000 (15:19 +0100)
committerKlaus Aehlig <aehlig@google.com>
Tue, 12 Jan 2016 09:17:35 +0000 (10:17 +0100)
ByteStrings are a more compact representation of a sequence of octets
than are Strings. However, converting a String into a ByteString, even
a lazy one, looks at a huge number of characters before the first goes
out of scope; thus the String gets enforced effectively. As Strings,
as a list of unicode characters, have a quite memory-intense representation,
this loss of lazyness results in a memory spike that is quite significant,
at least for restricted environments like a Xen dom0, when sending the
whole Ganeti configuration.

Therefore, send messages as String over the wire to preserve lazyness.
This is sound, as our JSON representation is 7-bit clean, and hence
every character coincides with its UTF8 encoding. On a larger cluster,
this saved an order of magnitude in peak memory usage.

Signed-off-by: Klaus Aehlig <aehlig@google.com>
Reviewed-by: Lisa Velden <velden@google.com>

src/Ganeti/UDSServer.hs

index 868c4e9..a374f69 100644 (file)
@@ -83,7 +83,7 @@ import Data.List
 import Data.Word (Word8)
 import qualified Network.Socket as S
 import System.Directory (removeFile)
-import System.IO (hClose, hFlush, hWaitForInput, Handle, IOMode(..))
+import System.IO (hClose, hFlush, hPutStr, hWaitForInput, Handle, IOMode(..))
 import System.IO.Error (isEOFError)
 import System.Posix.Types (Fd)
 import System.Posix.IO (createPipe, fdToHandle, handleToFd)
@@ -286,9 +286,8 @@ clientToFd client | rh == wh  = join (,) <$> handleToFd rh
 -- | Sends a message over a transport.
 sendMsg :: Client -> String -> IO ()
 sendMsg s buf = withTimeout (sendTmo $ clientConfig s) "sending a message" $ do
-  let encoded = UTF8.fromString buf
-      handle = wsocket s
-  B.hPut handle encoded
+  let handle = wsocket s
+  hPutStr handle buf
   B.hPut handle bEOM
   hFlush handle