Use incremental UTF-8 decoder for buffered reading
This commit is contained in:
+12
-9
@@ -63,7 +63,7 @@ from time import sleep
|
|||||||
from mininet.log import info, error, warn, debug
|
from mininet.log import info, error, warn, debug
|
||||||
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
|
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
|
||||||
numCores, retry, mountCgroups, BaseString, decode,
|
numCores, retry, mountCgroups, BaseString, decode,
|
||||||
encode, Python3, which )
|
encode, getincrementaldecoder, Python3, which )
|
||||||
from mininet.moduledeps import moduleDeps, pathCheck, TUN
|
from mininet.moduledeps import moduleDeps, pathCheck, TUN
|
||||||
from mininet.link import Link, Intf, TCIntf, OVSIntf
|
from mininet.link import Link, Intf, TCIntf, OVSIntf
|
||||||
from re import findall
|
from re import findall
|
||||||
@@ -106,6 +106,9 @@ class Node( object ):
|
|||||||
self.waiting = False
|
self.waiting = False
|
||||||
self.readbuf = ''
|
self.readbuf = ''
|
||||||
|
|
||||||
|
# Incremental decoder for buffered reading
|
||||||
|
self.decoder = getincrementaldecoder()
|
||||||
|
|
||||||
# Start command interpreter shell
|
# Start command interpreter shell
|
||||||
self.master, self.slave = None, None # pylint
|
self.master, self.slave = None, None # pylint
|
||||||
self.startShell()
|
self.startShell()
|
||||||
@@ -229,19 +232,19 @@ class Node( object ):
|
|||||||
|
|
||||||
# Subshell I/O, commands and control
|
# Subshell I/O, commands and control
|
||||||
|
|
||||||
def read( self, maxbytes=1024 ):
|
def read( self, size=1024 ):
|
||||||
"""Buffered read from node, potentially blocking.
|
"""Buffered read from node, potentially blocking.
|
||||||
maxbytes: maximum number of bytes to return"""
|
size: maximum number of characters to return"""
|
||||||
count = len( self.readbuf )
|
count = len( self.readbuf )
|
||||||
if count < maxbytes:
|
if count < size:
|
||||||
data = decode( os.read( self.stdout.fileno(), maxbytes - count ) )
|
data = os.read( self.stdout.fileno(), size - count )
|
||||||
self.readbuf += data
|
self.readbuf += self.decoder.decode( data )
|
||||||
if maxbytes >= len( self.readbuf ):
|
if size >= len( self.readbuf ):
|
||||||
result = self.readbuf
|
result = self.readbuf
|
||||||
self.readbuf = ''
|
self.readbuf = ''
|
||||||
else:
|
else:
|
||||||
result = self.readbuf[ :maxbytes ]
|
result = self.readbuf[ :size ]
|
||||||
self.readbuf = self.readbuf[ maxbytes: ]
|
self.readbuf = self.readbuf[ size: ]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def readline( self ):
|
def readline( self ):
|
||||||
|
|||||||
+56
-25
@@ -13,23 +13,48 @@ from os import O_NONBLOCK
|
|||||||
import os
|
import os
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import sys
|
import sys
|
||||||
|
import codecs
|
||||||
|
|
||||||
# Python 2/3 compatibility
|
# Python 2/3 compatibility
|
||||||
|
|
||||||
Python3 = sys.version_info[0] == 3
|
Python3 = sys.version_info[0] == 3
|
||||||
BaseString = str if Python3 else getattr( str, '__base__' )
|
BaseString = str if Python3 else getattr( str, '__base__' )
|
||||||
Encoding = 'utf-8' if Python3 else None
|
Encoding = 'utf-8' if Python3 else None
|
||||||
def decode( s ):
|
class NullCodec( object ):
|
||||||
"Decode a byte string if needed for Python 3"
|
"Null codec for Python 2"
|
||||||
return s.decode( Encoding ) if Python3 else s
|
@staticmethod
|
||||||
def encode( s ):
|
def decode( buf ):
|
||||||
"Encode a byte string if needed for Python 3"
|
"Null decode"
|
||||||
return s.encode( Encoding ) if Python3 else s
|
return buf
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def encode( buf ):
|
||||||
|
"Null encode"
|
||||||
|
return buf
|
||||||
|
|
||||||
|
|
||||||
|
if Python3:
|
||||||
|
def decode( buf ):
|
||||||
|
"Decode buffer for Python 3"
|
||||||
|
return buf.decode( Encoding )
|
||||||
|
|
||||||
|
def encode( buf ):
|
||||||
|
"Encode buffer for Python 3"
|
||||||
|
return buf.encode( Encoding )
|
||||||
|
getincrementaldecoder = codecs.getincrementaldecoder( Encoding )
|
||||||
|
else:
|
||||||
|
decode, encode = NullCodec.decode, NullCodec.encode
|
||||||
|
|
||||||
|
def getincrementaldecoder():
|
||||||
|
"Return null codec for Python 2"
|
||||||
|
return NullCodec
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# pylint: disable=import-error
|
# pylint: disable=import-error
|
||||||
oldpexpect = None
|
oldpexpect = None
|
||||||
import pexpect as oldpexpect
|
import pexpect as oldpexpect
|
||||||
# pylint: enable=import-error
|
|
||||||
|
|
||||||
|
# pylint: enable=import-error
|
||||||
class Pexpect( object ):
|
class Pexpect( object ):
|
||||||
"Custom pexpect that is compatible with str"
|
"Custom pexpect that is compatible with str"
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -119,20 +144,21 @@ def errRun( *cmd, **kwargs ):
|
|||||||
out, err = '', ''
|
out, err = '', ''
|
||||||
poller = poll()
|
poller = poll()
|
||||||
poller.register( popen.stdout, POLLIN )
|
poller.register( popen.stdout, POLLIN )
|
||||||
fdtofile = { popen.stdout.fileno(): popen.stdout }
|
fdToFile = { popen.stdout.fileno(): popen.stdout }
|
||||||
|
fdToDecoder = { popen.stdout.fileno(): getincrementaldecoder() }
|
||||||
outDone, errDone = False, True
|
outDone, errDone = False, True
|
||||||
if popen.stderr:
|
if popen.stderr:
|
||||||
fdtofile[ popen.stderr.fileno() ] = popen.stderr
|
fdToFile[ popen.stderr.fileno() ] = popen.stderr
|
||||||
|
fdToDecoder[ popen.stderr.fileno() ] = getincrementaldecoder()
|
||||||
poller.register( popen.stderr, POLLIN )
|
poller.register( popen.stderr, POLLIN )
|
||||||
errDone = False
|
errDone = False
|
||||||
while not outDone or not errDone:
|
while not outDone or not errDone:
|
||||||
readable = poller.poll()
|
readable = poller.poll()
|
||||||
for fd, event in readable:
|
for fd, event in readable:
|
||||||
f = fdtofile[ fd ]
|
f = fdToFile[ fd ]
|
||||||
|
decoder = fdToDecoder[ fd ]
|
||||||
if event & POLLIN:
|
if event & POLLIN:
|
||||||
data = f.read( 1024 )
|
data = decoder.decode( f.read( 1024 ) )
|
||||||
if Python3:
|
|
||||||
data = data.decode( Encoding )
|
|
||||||
if echo:
|
if echo:
|
||||||
output( data )
|
output( data )
|
||||||
if f == popen.stdout:
|
if f == popen.stdout:
|
||||||
@@ -187,8 +213,10 @@ def isShellBuiltin( cmd ):
|
|||||||
cmd = cmd[ :space]
|
cmd = cmd[ :space]
|
||||||
return cmd in isShellBuiltin.builtIns
|
return cmd in isShellBuiltin.builtIns
|
||||||
|
|
||||||
|
|
||||||
isShellBuiltin.builtIns = None
|
isShellBuiltin.builtIns = None
|
||||||
|
|
||||||
|
|
||||||
# Interface management
|
# Interface management
|
||||||
#
|
#
|
||||||
# Interfaces are managed as strings which are simply the
|
# Interfaces are managed as strings which are simply the
|
||||||
@@ -375,7 +403,7 @@ def netParse( ipstr ):
|
|||||||
if '/' in ipstr:
|
if '/' in ipstr:
|
||||||
ip, pf = ipstr.split( '/' )
|
ip, pf = ipstr.split( '/' )
|
||||||
prefixLen = int( pf )
|
prefixLen = int( pf )
|
||||||
#if no prefix is specified, set the prefix to 24
|
# if no prefix is specified, set the prefix to 24
|
||||||
else:
|
else:
|
||||||
ip = ipstr
|
ip = ipstr
|
||||||
prefixLen = 24
|
prefixLen = 24
|
||||||
@@ -418,9 +446,11 @@ def pmonitor(popens, timeoutms=500, readline=True,
|
|||||||
terminates: when all EOFs received"""
|
terminates: when all EOFs received"""
|
||||||
poller = poll()
|
poller = poll()
|
||||||
fdToHost = {}
|
fdToHost = {}
|
||||||
|
fdToDecoder = {}
|
||||||
for host, popen in popens.items():
|
for host, popen in popens.items():
|
||||||
fd = popen.stdout.fileno()
|
fd = popen.stdout.fileno()
|
||||||
fdToHost[ fd ] = host
|
fdToHost[ fd ] = host
|
||||||
|
fdToDecoder[ fd ] = getincrementaldecoder()
|
||||||
poller.register( fd, POLLIN | POLLHUP )
|
poller.register( fd, POLLIN | POLLHUP )
|
||||||
flags = fcntl( fd, F_GETFL )
|
flags = fcntl( fd, F_GETFL )
|
||||||
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
|
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
|
||||||
@@ -429,13 +459,14 @@ def pmonitor(popens, timeoutms=500, readline=True,
|
|||||||
if fds:
|
if fds:
|
||||||
for fd, event in fds:
|
for fd, event in fds:
|
||||||
host = fdToHost[ fd ]
|
host = fdToHost[ fd ]
|
||||||
|
decoder = fdToDecoder[ fd ]
|
||||||
popen = popens[ host ]
|
popen = popens[ host ]
|
||||||
if event & POLLIN or event & POLLHUP:
|
if event & POLLIN or event & POLLHUP:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
f = popen.stdout
|
f = popen.stdout
|
||||||
line = decode( f.readline() if readline
|
line = decoder.decode( f.readline() if readline
|
||||||
else f.read( readmax ) )
|
else f.read( readmax ) )
|
||||||
except IOError:
|
except IOError:
|
||||||
line = ''
|
line = ''
|
||||||
if line == '':
|
if line == '':
|
||||||
@@ -450,19 +481,19 @@ def pmonitor(popens, timeoutms=500, readline=True,
|
|||||||
# Other stuff we use
|
# Other stuff we use
|
||||||
def sysctlTestAndSet( name, limit ):
|
def sysctlTestAndSet( name, limit ):
|
||||||
"Helper function to set sysctl limits"
|
"Helper function to set sysctl limits"
|
||||||
#convert non-directory names into directory names
|
# convert non-directory names into directory names
|
||||||
if '/' not in name:
|
if '/' not in name:
|
||||||
name = '/proc/sys/' + name.replace( '.', '/' )
|
name = '/proc/sys/' + name.replace( '.', '/' )
|
||||||
#read limit
|
# read limit
|
||||||
with open( name, 'r' ) as readFile:
|
with open( name, 'r' ) as readFile:
|
||||||
oldLimit = readFile.readline()
|
oldLimit = readFile.readline()
|
||||||
if isinstance( limit, int ):
|
if isinstance( limit, int ):
|
||||||
#compare integer limits before overriding
|
# compare integer limits before overriding
|
||||||
if int( oldLimit ) < limit:
|
if int( oldLimit ) < limit:
|
||||||
with open( name, 'w' ) as writeFile:
|
with open( name, 'w' ) as writeFile:
|
||||||
writeFile.write( "%d" % limit )
|
writeFile.write( "%d" % limit )
|
||||||
else:
|
else:
|
||||||
#overwrite non-integer limits
|
# overwrite non-integer limits
|
||||||
with open( name, 'w' ) as writeFile:
|
with open( name, 'w' ) as writeFile:
|
||||||
writeFile.write( limit )
|
writeFile.write( limit )
|
||||||
|
|
||||||
@@ -479,21 +510,21 @@ def fixLimits():
|
|||||||
try:
|
try:
|
||||||
rlimitTestAndSet( RLIMIT_NPROC, 8192 )
|
rlimitTestAndSet( RLIMIT_NPROC, 8192 )
|
||||||
rlimitTestAndSet( RLIMIT_NOFILE, 16384 )
|
rlimitTestAndSet( RLIMIT_NOFILE, 16384 )
|
||||||
#Increase open file limit
|
# Increase open file limit
|
||||||
sysctlTestAndSet( 'fs.file-max', 10000 )
|
sysctlTestAndSet( 'fs.file-max', 10000 )
|
||||||
#Increase network buffer space
|
# Increase network buffer space
|
||||||
sysctlTestAndSet( 'net.core.wmem_max', 16777216 )
|
sysctlTestAndSet( 'net.core.wmem_max', 16777216 )
|
||||||
sysctlTestAndSet( 'net.core.rmem_max', 16777216 )
|
sysctlTestAndSet( 'net.core.rmem_max', 16777216 )
|
||||||
sysctlTestAndSet( 'net.ipv4.tcp_rmem', '10240 87380 16777216' )
|
sysctlTestAndSet( 'net.ipv4.tcp_rmem', '10240 87380 16777216' )
|
||||||
sysctlTestAndSet( 'net.ipv4.tcp_wmem', '10240 87380 16777216' )
|
sysctlTestAndSet( 'net.ipv4.tcp_wmem', '10240 87380 16777216' )
|
||||||
sysctlTestAndSet( 'net.core.netdev_max_backlog', 5000 )
|
sysctlTestAndSet( 'net.core.netdev_max_backlog', 5000 )
|
||||||
#Increase arp cache size
|
# Increase arp cache size
|
||||||
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh1', 4096 )
|
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh1', 4096 )
|
||||||
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh2', 8192 )
|
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh2', 8192 )
|
||||||
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh3', 16384 )
|
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh3', 16384 )
|
||||||
#Increase routing table size
|
# Increase routing table size
|
||||||
sysctlTestAndSet( 'net.ipv4.route.max_size', 32768 )
|
sysctlTestAndSet( 'net.ipv4.route.max_size', 32768 )
|
||||||
#Increase number of PTYs for nodes
|
# Increase number of PTYs for nodes
|
||||||
sysctlTestAndSet( 'kernel.pty.max', 20000 )
|
sysctlTestAndSet( 'kernel.pty.max', 20000 )
|
||||||
# pylint: disable=broad-except
|
# pylint: disable=broad-except
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|||||||
Reference in New Issue
Block a user