Просмотр исходного кода

When throttling, read and write in smaller chunks
* This is to avoid excessive latency due to long
sleeps in ratelimit.Reader and ratelimit.Writer.

Rod Hynes 9 лет назад
Родитель
Сommit
da7abf46bf
1 измененных файлов с 32 добавлено и 2 удалено
  1. 32 2
      psiphon/common/throttled.go

+ 32 - 2
psiphon/common/throttled.go

@@ -69,6 +69,8 @@ type ThrottledConn struct {
 	net.Conn
 }
 
+const chunkSize = 4096
+
 // NewThrottledConn initializes a new ThrottledConn.
 func NewThrottledConn(conn net.Conn, limits RateLimits) *ThrottledConn {
 
@@ -117,7 +119,14 @@ func (conn *ThrottledConn) Read(buffer []byte) (int, error) {
 		}
 	}
 
-	return conn.limitedReader.Read(buffer)
+	// When throttling, read small chunks to avoid
+	// excessive latency due to long waits in limitedReader.Read.
+
+	if len(buffer) <= chunkSize {
+		return conn.limitedReader.Read(buffer)
+	}
+
+	return conn.limitedReader.Read(buffer[0:chunkSize])
 }
 
 func (conn *ThrottledConn) Write(buffer []byte) (int, error) {
@@ -131,5 +140,26 @@ func (conn *ThrottledConn) Write(buffer []byte) (int, error) {
 		}
 	}
 
-	return conn.limitedWriter.Write(buffer)
+	// When throttling, write buffer in small chunks to avoid
+	// excessive latency due to long waits in limitedWriter.Write.
+
+	bytesWritten := 0
+
+	for i := 0; i < len(buffer); i += chunkSize {
+
+		start := i
+		end := start + chunkSize
+		if end > len(buffer) {
+			end = len(buffer)
+		}
+
+		n, err := conn.limitedWriter.Write(buffer[start:end])
+		bytesWritten += n
+		if err != nil {
+			// Note: no ContextError as caller may check for io.EOF, etc.
+			return bytesWritten, err
+		}
+	}
+
+	return bytesWritten, nil
 }