@ -1,13 +1,24 @@ 
			
		 
		
	
		
			
				 
				 
				package  util  
				 
				 
				package  util  
			
		 
		
	
		
			
				 
				 
				
 
				 
				 
				
 
			
		 
		
	
		
			
				 
				 
				import  (  
				 
				 
				import  (  
			
		 
		
	
		
			
				 
				 
					"github.com/seaweedfs/seaweedfs/weed/glog"  
				 
				 
				 
			
		 
		
	
		
			
				 
				 
					"net"  
				 
				 
					"net"  
			
		 
		
	
		
			
				 
				 
					"time"  
				 
				 
					"time"  
			
		 
		
	
		
			
				 
				 
				
 
				 
				 
				
 
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					"github.com/seaweedfs/seaweedfs/weed/glog"  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
				
 
			
		 
		
	
		
			
				 
				 
					"github.com/seaweedfs/seaweedfs/weed/stats"  
				 
				 
					"github.com/seaweedfs/seaweedfs/weed/stats"  
			
		 
		
	
		
			
				 
				 
				)  
				 
				 
				)  
			
		 
		
	
		
			
				 
				 
				
 
				 
				 
				
 
			
		 
		
	
		
			
				 
				 
				 
				 
				 
				const  (  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					// minThroughputBytesPerSecond defines the minimum expected throughput (4KB/s)
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					// Used to calculate timeout scaling based on data transferred
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					minThroughputBytesPerSecond  =  4000  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					 
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					// graceTimeCapMultiplier caps the grace period for slow clients at 3x base timeout
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					// This prevents indefinite connections while allowing time for server-side chunk fetches
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					graceTimeCapMultiplier  =  3  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
				)  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
				
 
			
		 
		
	
		
			
				 
				 
				// Listener wraps a net.Listener, and gives a place to store the timeout
  
				 
				 
				// Listener wraps a net.Listener, and gives a place to store the timeout
  
			
		 
		
	
		
			
				 
				 
				// parameters. On Accept, it will wrap the net.Conn with our own Conn for us.
  
				 
				 
				// parameters. On Accept, it will wrap the net.Conn with our own Conn for us.
  
			
		 
		
	
		
			
				 
				 
				type  Listener  struct  {  
				 
				 
				type  Listener  struct  {  
			
		 
		
	
	
		
			
				
					
						
							 
						 
					
					
						
							 
						 
					
					
				 
				@ -39,11 +50,28 @@ type Conn struct { 
			
		 
		
	
		
			
				 
				 
					isClosed      bool  
				 
				 
					isClosed      bool  
			
		 
		
	
		
			
				 
				 
					bytesRead     int64  
				 
				 
					bytesRead     int64  
			
		 
		
	
		
			
				 
				 
					bytesWritten  int64  
				 
				 
					bytesWritten  int64  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					lastWrite     time . Time  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
				}  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
				
 
			
		 
		
	
		
			
				 
				 
				 
				 
				 
				// calculateBytesPerTimeout calculates the expected number of bytes that should
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
				// be transferred during one timeout period, based on the minimum throughput.
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
				// Returns at least 1 to prevent division by zero.
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
				func  calculateBytesPerTimeout ( timeout  time . Duration )  int64  {  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					bytesPerTimeout  :=  int64 ( float64 ( minThroughputBytesPerSecond )  *  timeout . Seconds ( ) )  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					if  bytesPerTimeout  <=  0  {  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						return  1  // Prevent division by zero
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					}  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
					return  bytesPerTimeout  
			
		 
		
	
		
			
				 
				 
				}  
				 
				 
				}  
			
		 
		
	
		
			
				 
				 
				
 
				 
				 
				
 
			
		 
		
	
		
			
				 
				 
				func  ( c  * Conn )  Read ( b  [ ] byte )  ( count  int ,  e  error )  {  
				 
				 
				func  ( c  * Conn )  Read ( b  [ ] byte )  ( count  int ,  e  error )  {  
			
		 
		
	
		
			
				 
				 
					if  c . ReadTimeout  !=  0  {  
				 
				 
					if  c . ReadTimeout  !=  0  {  
			
		 
		
	
		
			
				 
				 
						err  :=  c . Conn . SetReadDeadline ( time . Now ( ) . Add ( c . ReadTimeout  *  time . Duration ( c . bytesRead / 40000 + 1 ) ) )  
				 
				 
				 
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// Calculate expected bytes per timeout period based on minimum throughput (4KB/s)
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// Example: with ReadTimeout=30s, bytesPerTimeout = 4000 * 30 = 120KB
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// After reading 1MB: multiplier = 1,000,000/120,000 + 1 ≈ 9, deadline = 30s * 9 = 270s
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						bytesPerTimeout  :=  calculateBytesPerTimeout ( c . ReadTimeout )  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						timeoutMultiplier  :=  time . Duration ( c . bytesRead / bytesPerTimeout  +  1 )  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						err  :=  c . Conn . SetReadDeadline ( time . Now ( ) . Add ( c . ReadTimeout  *  timeoutMultiplier ) )  
			
		 
		
	
		
			
				 
				 
						if  err  !=  nil  {  
				 
				 
						if  err  !=  nil  {  
			
		 
		
	
		
			
				 
				 
							return  0 ,  err  
				 
				 
							return  0 ,  err  
			
		 
		
	
		
			
				 
				 
						}  
				 
				 
						}  
			
		 
		
	
	
		
			
				
					
					
					
						
							 
						 
					
				 
				@ -58,8 +86,42 @@ func (c *Conn) Read(b []byte) (count int, e error) { 
			
		 
		
	
		
			
				 
				 
				
 
				 
				 
				
 
			
		 
		
	
		
			
				 
				 
				func  ( c  * Conn )  Write ( b  [ ] byte )  ( count  int ,  e  error )  {  
				 
				 
				func  ( c  * Conn )  Write ( b  [ ] byte )  ( count  int ,  e  error )  {  
			
		 
		
	
		
			
				 
				 
					if  c . WriteTimeout  !=  0  {  
				 
				 
					if  c . WriteTimeout  !=  0  {  
			
		 
		
	
		
			
				 
				 
						// minimum 4KB/s
  
				 
				 
				 
			
		 
		
	
		
			
				 
				 
						err  :=  c . Conn . SetWriteDeadline ( time . Now ( ) . Add ( c . WriteTimeout  *  time . Duration ( c . bytesWritten / 40000 + 1 ) ) )  
				 
				 
				 
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						now  :=  time . Now ( )  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// Calculate timeout with two components:
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// 1. Base timeout scaled by cumulative data (minimum throughput of 4KB/s)
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// 2. Additional grace period if there was a gap since last write (for chunk fetch delays)
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						 
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// Calculate expected bytes per timeout period based on minimum throughput (4KB/s)
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// Example: with WriteTimeout=30s, bytesPerTimeout = 4000 * 30 = 120KB
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// After writing 1MB: multiplier = 1,000,000/120,000 + 1 ≈ 9, baseTimeout = 30s * 9 = 270s
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						bytesPerTimeout  :=  calculateBytesPerTimeout ( c . WriteTimeout )  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						timeoutMultiplier  :=  time . Duration ( c . bytesWritten / bytesPerTimeout  +  1 )  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						baseTimeout  :=  c . WriteTimeout  *  timeoutMultiplier  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						 
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// If it's been a while since last write, add grace time for server-side chunk fetches
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// But cap it to avoid keeping slow clients connected indefinitely
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// 
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// The comparison uses unscaled WriteTimeout intentionally: triggers grace when idle time
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						// exceeds base timeout, independent of throughput scaling.
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						if  ! c . lastWrite . IsZero ( )  {  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
							timeSinceLastWrite  :=  now . Sub ( c . lastWrite )  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
							if  timeSinceLastWrite  >  c . WriteTimeout  {  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
								// Add grace time capped at graceTimeCapMultiplier * scaled timeout.
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
								// This allows total deadline up to 4x scaled timeout for server-side delays.
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
								//
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
								// Example: WriteTimeout=30s, 1MB written (multiplier≈9), baseTimeout=270s
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
								// If 400s gap occurs fetching chunks: graceTime capped at 270s*3=810s
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
								// Final deadline: 270s + 810s = 1080s (~18min) to accommodate slow storage
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
								// But if only 50s gap: graceTime = 50s, final deadline = 270s + 50s = 320s
  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
								graceTime  :=  timeSinceLastWrite  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
								if  graceTime  >  baseTimeout * graceTimeCapMultiplier  {  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
									graceTime  =  baseTimeout  *  graceTimeCapMultiplier  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
								}  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
								baseTimeout  +=  graceTime  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
							}  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						}  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						 
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						err  :=  c . Conn . SetWriteDeadline ( now . Add ( baseTimeout ) )  
			
		 
		
	
		
			
				 
				 
						if  err  !=  nil  {  
				 
				 
						if  err  !=  nil  {  
			
		 
		
	
		
			
				 
				 
							return  0 ,  err  
				 
				 
							return  0 ,  err  
			
		 
		
	
		
			
				 
				 
						}  
				 
				 
						}  
			
		 
		
	
	
		
			
				
					
					
					
						
							 
						 
					
				 
				@ -68,6 +130,7 @@ func (c *Conn) Write(b []byte) (count int, e error) { 
			
		 
		
	
		
			
				 
				 
					if  e  ==  nil  {  
				 
				 
					if  e  ==  nil  {  
			
		 
		
	
		
			
				 
				 
						stats . BytesOut ( int64 ( count ) )  
				 
				 
						stats . BytesOut ( int64 ( count ) )  
			
		 
		
	
		
			
				 
				 
						c . bytesWritten  +=  int64 ( count )  
				 
				 
						c . bytesWritten  +=  int64 ( count )  
			
		 
		
	
		
			
				 
				 
				 
				 
				 
						c . lastWrite  =  time . Now ( )  
			
		 
		
	
		
			
				 
				 
					}  
				 
				 
					}  
			
		 
		
	
		
			
				 
				 
					return  
				 
				 
					return  
			
		 
		
	
		
			
				 
				 
				}  
				 
				 
				}