mirror of
https://github.com/ehang-io/nps.git
synced 2025-07-05 06:40:43 +00:00
change slide window design
This commit is contained in:
parent
4ea5478241
commit
aad7ed8f24
@ -162,10 +162,9 @@ func (Self *ConnPackager) UnPack(reader io.Reader) (n uint16, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MuxPackager struct {
|
type MuxPackager struct {
|
||||||
Flag uint8
|
Flag uint8
|
||||||
Id int32
|
Id int32
|
||||||
Window uint32
|
Window uint64
|
||||||
ReadLength uint32
|
|
||||||
BasePackager
|
BasePackager
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,19 +177,8 @@ func (Self *MuxPackager) NewPac(flag uint8, id int32, content ...interface{}) (e
|
|||||||
err = Self.BasePackager.NewPac(content...)
|
err = Self.BasePackager.NewPac(content...)
|
||||||
//logs.Warn(Self.Length, string(Self.Content))
|
//logs.Warn(Self.Length, string(Self.Content))
|
||||||
case MUX_MSG_SEND_OK:
|
case MUX_MSG_SEND_OK:
|
||||||
// MUX_MSG_SEND_OK contains two data
|
// MUX_MSG_SEND_OK contains one data
|
||||||
switch content[0].(type) {
|
Self.Window = content[0].(uint64)
|
||||||
case int:
|
|
||||||
Self.Window = uint32(content[0].(int))
|
|
||||||
case uint32:
|
|
||||||
Self.Window = content[0].(uint32)
|
|
||||||
}
|
|
||||||
switch content[1].(type) {
|
|
||||||
case int:
|
|
||||||
Self.ReadLength = uint32(content[1].(int))
|
|
||||||
case uint32:
|
|
||||||
Self.ReadLength = content[1].(uint32)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -210,10 +198,6 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) {
|
|||||||
WindowBuff.Put(Self.Content)
|
WindowBuff.Put(Self.Content)
|
||||||
case MUX_MSG_SEND_OK:
|
case MUX_MSG_SEND_OK:
|
||||||
err = binary.Write(writer, binary.LittleEndian, Self.Window)
|
err = binary.Write(writer, binary.LittleEndian, Self.Window)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = binary.Write(writer, binary.LittleEndian, Self.ReadLength)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -235,12 +219,7 @@ func (Self *MuxPackager) UnPack(reader io.Reader) (n uint16, err error) {
|
|||||||
//logs.Warn("unpack", Self.Length, string(Self.Content))
|
//logs.Warn("unpack", Self.Length, string(Self.Content))
|
||||||
case MUX_MSG_SEND_OK:
|
case MUX_MSG_SEND_OK:
|
||||||
err = binary.Read(reader, binary.LittleEndian, &Self.Window)
|
err = binary.Read(reader, binary.LittleEndian, &Self.Window)
|
||||||
if err != nil {
|
n += 8 // uint64
|
||||||
return
|
|
||||||
}
|
|
||||||
n += 4 // uint32
|
|
||||||
err = binary.Read(reader, binary.LittleEndian, &Self.ReadLength)
|
|
||||||
n += 4 // uint32
|
|
||||||
}
|
}
|
||||||
n += 5 //uint8 int32
|
n += 5 //uint8 int32
|
||||||
return
|
return
|
||||||
@ -251,7 +230,6 @@ func (Self *MuxPackager) reset() {
|
|||||||
Self.Flag = 0
|
Self.Flag = 0
|
||||||
Self.Length = 0
|
Self.Length = 0
|
||||||
Self.Content = nil
|
Self.Content = nil
|
||||||
Self.ReadLength = 0
|
|
||||||
Self.Window = 0
|
Self.Window = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
276
lib/mux/conn.go
276
lib/mux/conn.go
@ -3,6 +3,7 @@ package mux
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
@ -10,8 +11,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cnlh/nps/lib/common"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type conn struct {
|
type conn struct {
|
||||||
@ -146,25 +145,44 @@ func (s *conn) SetWriteDeadline(t time.Time) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type window struct {
|
type window struct {
|
||||||
remainingWait uint64 // 64bit alignment
|
maxSizeDone uint64
|
||||||
off uint32
|
// 64bit alignment
|
||||||
maxSize uint32
|
// maxSizeDone contains 4 parts
|
||||||
closeOp bool
|
// 1 31 1 31
|
||||||
closeOpCh chan struct{}
|
// wait maxSize useless done
|
||||||
mux *Mux
|
// wait zero means false, one means true
|
||||||
|
off uint32
|
||||||
|
closeOp bool
|
||||||
|
closeOpCh chan struct{}
|
||||||
|
mux *Mux
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *window) unpack(ptrs uint64) (remaining, wait uint32) {
|
const windowBits = 31
|
||||||
const mask = 1<<dequeueBits - 1
|
const waitBits = dequeueBits + windowBits
|
||||||
remaining = uint32((ptrs >> dequeueBits) & mask)
|
const mask1 = 1
|
||||||
wait = uint32(ptrs & mask)
|
const mask31 = 1<<windowBits - 1
|
||||||
|
|
||||||
|
func (Self *window) unpack(ptrs uint64) (maxSize, done uint32, wait bool) {
|
||||||
|
maxSize = uint32((ptrs >> dequeueBits) & mask31)
|
||||||
|
done = uint32(ptrs & mask31)
|
||||||
|
//logs.Warn("unpack", maxSize, done)
|
||||||
|
if ((ptrs >> waitBits) & mask1) == 1 {
|
||||||
|
wait = true
|
||||||
|
return
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *window) pack(remaining, wait uint32) uint64 {
|
func (Self *window) pack(maxSize, done uint32, wait bool) uint64 {
|
||||||
const mask = 1<<dequeueBits - 1
|
//logs.Warn("pack", maxSize, done, wait)
|
||||||
return (uint64(remaining) << dequeueBits) |
|
if wait {
|
||||||
uint64(wait&mask)
|
return (uint64(1)<<waitBits |
|
||||||
|
uint64(maxSize&mask31)<<dequeueBits) |
|
||||||
|
uint64(done&mask31)
|
||||||
|
}
|
||||||
|
return (uint64(0)<<waitBits |
|
||||||
|
uint64(maxSize&mask31)<<dequeueBits) |
|
||||||
|
uint64(done&mask31)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *window) New() {
|
func (Self *window) New() {
|
||||||
@ -185,20 +203,22 @@ type ReceiveWindow struct {
|
|||||||
element *common.ListElement
|
element *common.ListElement
|
||||||
count int8
|
count int8
|
||||||
once sync.Once
|
once sync.Once
|
||||||
|
// receive window send the current max size and read size to send window
|
||||||
|
// means done size actually store the size receive window has read
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *ReceiveWindow) New(mux *Mux) {
|
func (Self *ReceiveWindow) New(mux *Mux) {
|
||||||
// initial a window for receive
|
// initial a window for receive
|
||||||
Self.bufQueue.New()
|
Self.bufQueue.New()
|
||||||
Self.element = common.ListElementPool.Get()
|
Self.element = common.ListElementPool.Get()
|
||||||
Self.maxSize = common.MAXIMUM_SEGMENT_SIZE * 10
|
Self.maxSizeDone = Self.pack(common.MAXIMUM_SEGMENT_SIZE*10, 0, false)
|
||||||
Self.mux = mux
|
Self.mux = mux
|
||||||
Self.window.New()
|
Self.window.New()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *ReceiveWindow) remainingSize(delta uint16) (n uint32) {
|
func (Self *ReceiveWindow) remainingSize(maxSize uint32, delta uint16) (n uint32) {
|
||||||
// receive window remaining
|
// receive window remaining
|
||||||
l := int64(atomic.LoadUint32(&Self.maxSize)) - int64(Self.bufQueue.Len())
|
l := int64(maxSize) - int64(Self.bufQueue.Len())
|
||||||
l -= int64(delta)
|
l -= int64(delta)
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
n = uint32(l)
|
n = uint32(l)
|
||||||
@ -213,27 +233,33 @@ func (Self *ReceiveWindow) calcSize() {
|
|||||||
conns := Self.mux.connMap.Size()
|
conns := Self.mux.connMap.Size()
|
||||||
n := uint32(math.Float64frombits(atomic.LoadUint64(&Self.mux.latency)) *
|
n := uint32(math.Float64frombits(atomic.LoadUint64(&Self.mux.latency)) *
|
||||||
Self.mux.bw.Get() / float64(conns))
|
Self.mux.bw.Get() / float64(conns))
|
||||||
|
//logs.Warn(n)
|
||||||
if n < common.MAXIMUM_SEGMENT_SIZE*10 {
|
if n < common.MAXIMUM_SEGMENT_SIZE*10 {
|
||||||
n = common.MAXIMUM_SEGMENT_SIZE * 10
|
n = common.MAXIMUM_SEGMENT_SIZE * 10
|
||||||
}
|
}
|
||||||
//bufLen := Self.bufQueue.Len()
|
for {
|
||||||
//if n < bufLen {
|
ptrs := atomic.LoadUint64(&Self.maxSizeDone)
|
||||||
// n = bufLen
|
size, read, wait := Self.unpack(ptrs)
|
||||||
//}
|
if n < size/2 {
|
||||||
if n < Self.maxSize/2 {
|
n = size / 2
|
||||||
n = Self.maxSize / 2
|
// half reduce
|
||||||
|
}
|
||||||
|
// set the minimal size
|
||||||
|
if n > 2*size {
|
||||||
|
n = 2 * size
|
||||||
|
// twice grow
|
||||||
|
}
|
||||||
|
if n > (common.MAXIMUM_WINDOW_SIZE / uint32(conns)) {
|
||||||
|
//logs.Warn("window too large", n)
|
||||||
|
n = common.MAXIMUM_WINDOW_SIZE / uint32(conns)
|
||||||
|
}
|
||||||
|
// set the maximum size
|
||||||
|
//logs.Warn("n", n)
|
||||||
|
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(n, read, wait)) {
|
||||||
|
// only change the maxSize
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// set the minimal size
|
|
||||||
if n > 2*Self.maxSize {
|
|
||||||
n = 2 * Self.maxSize
|
|
||||||
}
|
|
||||||
if n > (common.MAXIMUM_WINDOW_SIZE / uint32(conns)) {
|
|
||||||
logs.Warn("window too large", n)
|
|
||||||
n = common.MAXIMUM_WINDOW_SIZE / uint32(conns)
|
|
||||||
}
|
|
||||||
// set the maximum size
|
|
||||||
//logs.Warn("n", n)
|
|
||||||
atomic.StoreUint32(&Self.maxSize, n)
|
|
||||||
Self.count = -10
|
Self.count = -10
|
||||||
}
|
}
|
||||||
Self.count += 1
|
Self.count += 1
|
||||||
@ -245,30 +271,40 @@ func (Self *ReceiveWindow) Write(buf []byte, l uint16, part bool, id int32) (err
|
|||||||
return errors.New("conn.receiveWindow: write on closed window")
|
return errors.New("conn.receiveWindow: write on closed window")
|
||||||
}
|
}
|
||||||
element, err := NewListElement(buf, l, part)
|
element, err := NewListElement(buf, l, part)
|
||||||
//logs.Warn("push the buf", len(buf), l, (&element).l)
|
//logs.Warn("push the buf", len(buf), l, element.L)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Self.calcSize() // calculate the max window size
|
Self.calcSize() // calculate the max window size
|
||||||
var wait uint32
|
var wait bool
|
||||||
|
var maxSize, read uint32
|
||||||
start:
|
start:
|
||||||
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
ptrs := atomic.LoadUint64(&Self.maxSizeDone)
|
||||||
_, wait = Self.unpack(ptrs)
|
maxSize, read, wait = Self.unpack(ptrs)
|
||||||
newRemaining := Self.remainingSize(l)
|
remain := Self.remainingSize(maxSize, l)
|
||||||
// calculate the remaining window size now, plus the element we will push
|
// calculate the remaining window size now, plus the element we will push
|
||||||
if newRemaining == 0 {
|
if remain == 0 && !wait {
|
||||||
//logs.Warn("window full true", remaining)
|
//logs.Warn("window full true", remaining)
|
||||||
wait = 1
|
wait = true
|
||||||
}
|
if !atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, read, wait)) {
|
||||||
if !atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(0, wait)) {
|
// only change the wait status, not send the read size
|
||||||
goto start
|
goto start
|
||||||
// another goroutine change the status, make sure shall we need wait
|
// another goroutine change the status, make sure shall we need wait
|
||||||
}
|
}
|
||||||
|
//logs.Warn("receive window full")
|
||||||
|
} else if !wait {
|
||||||
|
if !atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, 0, wait)) {
|
||||||
|
// reset read size here, and send the read size directly
|
||||||
|
goto start
|
||||||
|
// another goroutine change the status, make sure shall we need wait
|
||||||
|
}
|
||||||
|
} // maybe there are still some data received even if window is full, just keep the wait status
|
||||||
|
// and push into queue. when receive window read enough, send window will be acknowledged.
|
||||||
Self.bufQueue.Push(element)
|
Self.bufQueue.Push(element)
|
||||||
// status check finish, now we can push the element into the queue
|
// status check finish, now we can push the element into the queue
|
||||||
if wait == 0 {
|
if !wait {
|
||||||
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, newRemaining)
|
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.pack(maxSize, read, false))
|
||||||
// send the remaining window size, not including zero size
|
// send the current status to send window
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -279,7 +315,7 @@ func (Self *ReceiveWindow) Read(p []byte, id int32) (n int, err error) {
|
|||||||
}
|
}
|
||||||
pOff := 0
|
pOff := 0
|
||||||
l := 0
|
l := 0
|
||||||
//logs.Warn("receive window read off, element.l", Self.off, Self.element.l)
|
//logs.Warn("receive window read off, element.l", Self.off, Self.element.L)
|
||||||
copyData:
|
copyData:
|
||||||
if Self.off == uint32(Self.element.L) {
|
if Self.off == uint32(Self.element.L) {
|
||||||
// on the first Read method invoked, Self.off and Self.element.l
|
// on the first Read method invoked, Self.off and Self.element.l
|
||||||
@ -291,14 +327,13 @@ copyData:
|
|||||||
Self.element, err = Self.bufQueue.Pop()
|
Self.element, err = Self.bufQueue.Pop()
|
||||||
// if the queue is empty, Pop method will wait until one element push
|
// if the queue is empty, Pop method will wait until one element push
|
||||||
// into the queue successful, or timeout.
|
// into the queue successful, or timeout.
|
||||||
// timer start on timeout parameter is set up ,
|
// timer start on timeout parameter is set up
|
||||||
// reset to 60s if timeout and data still available
|
|
||||||
Self.off = 0
|
Self.off = 0
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Self.CloseWindow() // also close the window, to avoid read twice
|
Self.CloseWindow() // also close the window, to avoid read twice
|
||||||
return // queue receive stop or time out, break the loop and return
|
return // queue receive stop or time out, break the loop and return
|
||||||
}
|
}
|
||||||
//logs.Warn("pop element", Self.element.l, Self.element.part)
|
//logs.Warn("pop element", Self.element.L, Self.element.Part)
|
||||||
}
|
}
|
||||||
l = copy(p[pOff:], Self.element.Buf[Self.off:Self.element.L])
|
l = copy(p[pOff:], Self.element.Buf[Self.off:Self.element.L])
|
||||||
pOff += l
|
pOff += l
|
||||||
@ -320,22 +355,41 @@ copyData:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (Self *ReceiveWindow) sendStatus(id int32, l uint16) {
|
func (Self *ReceiveWindow) sendStatus(id int32, l uint16) {
|
||||||
var remaining, wait uint32
|
var maxSize, read uint32
|
||||||
|
var wait bool
|
||||||
for {
|
for {
|
||||||
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
ptrs := atomic.LoadUint64(&Self.maxSizeDone)
|
||||||
remaining, wait = Self.unpack(ptrs)
|
maxSize, read, wait = Self.unpack(ptrs)
|
||||||
remaining += uint32(l)
|
if read <= (read+uint32(l))&mask31 {
|
||||||
if atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(remaining, 0)) {
|
read += uint32(l)
|
||||||
break
|
remain := Self.remainingSize(maxSize, 0)
|
||||||
|
if wait && remain > 0 || remain == maxSize {
|
||||||
|
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, 0, false)) {
|
||||||
|
// now we get the current window status success
|
||||||
|
// receive window free up some space we need acknowledge send window, also reset the read size
|
||||||
|
// still having a condition that receive window is empty and not send the status to send window
|
||||||
|
// so send the status here
|
||||||
|
//logs.Warn("receive window free up some space", remain)
|
||||||
|
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.pack(maxSize, read, false))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, read, wait)) {
|
||||||
|
// receive window not into the wait status, or still not having any space now,
|
||||||
|
// just change the read size
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//overflow
|
||||||
|
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, uint32(l), wait)) {
|
||||||
|
// reset to l
|
||||||
|
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.pack(maxSize, read, false))
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
runtime.Gosched()
|
runtime.Gosched()
|
||||||
// another goroutine change remaining or wait status, make sure
|
// another goroutine change remaining or wait status, make sure
|
||||||
// we need acknowledge other side
|
|
||||||
}
|
|
||||||
// now we get the current window status success
|
|
||||||
if wait == 1 {
|
|
||||||
//logs.Warn("send the wait status", remaining)
|
|
||||||
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, atomic.LoadUint32(&Self.maxSize), remaining)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -380,12 +434,14 @@ type SendWindow struct {
|
|||||||
buf []byte
|
buf []byte
|
||||||
setSizeCh chan struct{}
|
setSizeCh chan struct{}
|
||||||
timeout time.Time
|
timeout time.Time
|
||||||
|
// send window receive the receive window max size and read size
|
||||||
|
// done size store the size send window has send, send and read will be totally equal
|
||||||
|
// so send minus read, send window can get the current window size remaining
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *SendWindow) New(mux *Mux) {
|
func (Self *SendWindow) New(mux *Mux) {
|
||||||
Self.setSizeCh = make(chan struct{})
|
Self.setSizeCh = make(chan struct{})
|
||||||
Self.maxSize = common.MAXIMUM_SEGMENT_SIZE * 10
|
Self.maxSizeDone = Self.pack(common.MAXIMUM_SEGMENT_SIZE*10, 0, false)
|
||||||
atomic.AddUint64(&Self.remainingWait, uint64(common.MAXIMUM_SEGMENT_SIZE*10)<<dequeueBits)
|
|
||||||
Self.mux = mux
|
Self.mux = mux
|
||||||
Self.window.New()
|
Self.window.New()
|
||||||
}
|
}
|
||||||
@ -396,7 +452,15 @@ func (Self *SendWindow) SetSendBuf(buf []byte) {
|
|||||||
Self.off = 0
|
Self.off = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *SendWindow) SetSize(windowSize, newRemaining uint32) (closed bool) {
|
func (Self *SendWindow) remainingSize(maxSize, send uint32) uint32 {
|
||||||
|
l := int64(maxSize&mask31) - int64(send&mask31)
|
||||||
|
if l > 0 {
|
||||||
|
return uint32(l)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *SendWindow) SetSize(currentMaxSizeDone uint64) (closed bool) {
|
||||||
// set the window size from receive window
|
// set the window size from receive window
|
||||||
defer func() {
|
defer func() {
|
||||||
if recover() != nil {
|
if recover() != nil {
|
||||||
@ -408,26 +472,34 @@ func (Self *SendWindow) SetSize(windowSize, newRemaining uint32) (closed bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
//logs.Warn("set send window size to ", windowSize, newRemaining)
|
//logs.Warn("set send window size to ", windowSize, newRemaining)
|
||||||
var remaining, wait, newWait uint32
|
var maxsize, send uint32
|
||||||
|
var wait, newWait bool
|
||||||
|
currentMaxSize, read, _ := Self.unpack(currentMaxSizeDone)
|
||||||
for {
|
for {
|
||||||
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
ptrs := atomic.LoadUint64(&Self.maxSizeDone)
|
||||||
remaining, wait = Self.unpack(ptrs)
|
maxsize, send, wait = Self.unpack(ptrs)
|
||||||
if remaining == newRemaining {
|
if read > send {
|
||||||
//logs.Warn("waiting for another window size")
|
logs.Error("read > send")
|
||||||
return false // waiting for receive another usable window size
|
return
|
||||||
}
|
}
|
||||||
if newRemaining == 0 && wait == 1 {
|
if read == 0 && currentMaxSize == maxsize {
|
||||||
newWait = 1 // keep the wait status,
|
return
|
||||||
// also if newRemaining is not zero, change wait to 0
|
|
||||||
}
|
}
|
||||||
if atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(newRemaining, newWait)) {
|
send -= read
|
||||||
|
remain := Self.remainingSize(currentMaxSize, send)
|
||||||
|
if remain == 0 && wait {
|
||||||
|
// just keep the wait status
|
||||||
|
newWait = true
|
||||||
|
}
|
||||||
|
// remain > 0, change wait to false. or remain == 0, wait is false, just keep it
|
||||||
|
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(currentMaxSize, send, newWait)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// anther goroutine change wait status or window size
|
// anther goroutine change wait status or window size
|
||||||
}
|
}
|
||||||
if wait == 1 {
|
if wait && !newWait {
|
||||||
// send window into the wait status, need notice the channel
|
// send window into the wait status, need notice the channel
|
||||||
//logs.Warn("send window remaining size is 0")
|
//logs.Warn("send window allow")
|
||||||
Self.allow()
|
Self.allow()
|
||||||
}
|
}
|
||||||
// send window not into the wait status, so just do slide
|
// send window not into the wait status, so just do slide
|
||||||
@ -446,18 +518,20 @@ func (Self *SendWindow) allow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (Self *SendWindow) sent(sentSize uint32) {
|
func (Self *SendWindow) sent(sentSize uint32) {
|
||||||
var remaining, wait uint32
|
var maxSie, send uint32
|
||||||
|
var wait bool
|
||||||
for {
|
for {
|
||||||
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
ptrs := atomic.LoadUint64(&Self.maxSizeDone)
|
||||||
remaining, wait = Self.unpack(ptrs)
|
maxSie, send, wait = Self.unpack(ptrs)
|
||||||
if remaining >= sentSize {
|
if (send+sentSize)&mask31 < send {
|
||||||
atomic.AddUint64(&Self.remainingWait, ^(uint64(sentSize)<<dequeueBits - 1))
|
// overflow
|
||||||
|
runtime.Gosched()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSie, send+sentSize, wait)) {
|
||||||
|
// set the send size
|
||||||
|
//logs.Warn("sent", maxSie, send+sentSize, wait)
|
||||||
break
|
break
|
||||||
} else {
|
|
||||||
if atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(0, wait)) {
|
|
||||||
// just keep the wait status, it will be wait in the next loop
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -472,12 +546,14 @@ func (Self *SendWindow) WriteTo() (p []byte, sendSize uint32, part bool, err err
|
|||||||
return nil, 0, false, io.EOF
|
return nil, 0, false, io.EOF
|
||||||
// send window buff is drain, return eof and get another one
|
// send window buff is drain, return eof and get another one
|
||||||
}
|
}
|
||||||
var remaining uint32
|
var maxSize, send uint32
|
||||||
start:
|
start:
|
||||||
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
ptrs := atomic.LoadUint64(&Self.maxSizeDone)
|
||||||
remaining, _ = Self.unpack(ptrs)
|
maxSize, send, _ = Self.unpack(ptrs)
|
||||||
if remaining == 0 {
|
remain := Self.remainingSize(maxSize, send)
|
||||||
if !atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(0, 1)) {
|
if remain == 0 {
|
||||||
|
if !atomic.CompareAndSwapUint64(&Self.maxSizeDone, ptrs, Self.pack(maxSize, send, true)) {
|
||||||
|
// just change the status wait status
|
||||||
goto start // another goroutine change the window, try again
|
goto start // another goroutine change the window, try again
|
||||||
}
|
}
|
||||||
// into the wait status
|
// into the wait status
|
||||||
@ -490,17 +566,17 @@ start:
|
|||||||
goto start
|
goto start
|
||||||
}
|
}
|
||||||
// there are still remaining window
|
// there are still remaining window
|
||||||
//logs.Warn("rem", remaining)
|
//logs.Warn("rem", remain, maxSize, send)
|
||||||
if len(Self.buf[Self.off:]) > common.MAXIMUM_SEGMENT_SIZE {
|
if len(Self.buf[Self.off:]) > common.MAXIMUM_SEGMENT_SIZE {
|
||||||
sendSize = common.MAXIMUM_SEGMENT_SIZE
|
sendSize = common.MAXIMUM_SEGMENT_SIZE
|
||||||
//logs.Warn("cut buf by mss")
|
//logs.Warn("cut buf by mss")
|
||||||
} else {
|
} else {
|
||||||
sendSize = uint32(len(Self.buf[Self.off:]))
|
sendSize = uint32(len(Self.buf[Self.off:]))
|
||||||
}
|
}
|
||||||
if remaining < sendSize {
|
if remain < sendSize {
|
||||||
// usable window size is small than
|
// usable window size is small than
|
||||||
// window MAXIMUM_SEGMENT_SIZE or send buf left
|
// window MAXIMUM_SEGMENT_SIZE or send buf left
|
||||||
sendSize = remaining
|
sendSize = remain
|
||||||
//logs.Warn("cut buf by remainingsize", sendSize, len(Self.buf[Self.off:]))
|
//logs.Warn("cut buf by remainingsize", sendSize, len(Self.buf[Self.off:]))
|
||||||
}
|
}
|
||||||
//logs.Warn("send size", sendSize)
|
//logs.Warn("send size", sendSize)
|
||||||
|
@ -303,7 +303,7 @@ func (s *Mux) readSession() {
|
|||||||
if connection.isClose {
|
if connection.isClose {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
connection.sendWindow.SetSize(pack.Window, pack.ReadLength)
|
connection.sendWindow.SetSize(pack.Window)
|
||||||
continue
|
continue
|
||||||
case common.MUX_CONN_CLOSE: //close the connection
|
case common.MUX_CONN_CLOSE: //close the connection
|
||||||
connection.closeFlag = true
|
connection.closeFlag = true
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/cnlh/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"github.com/cnlh/nps/lib/goroutine"
|
"github.com/cnlh/nps/lib/goroutine"
|
||||||
"github.com/xtaci/kcp-go"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@ -34,8 +33,8 @@ func TestNewMux(t *testing.T) {
|
|||||||
//poolConnCopy, _ := ants.NewPoolWithFunc(200000, common.copyConn, ants.WithNonblocking(false))
|
//poolConnCopy, _ := ants.NewPoolWithFunc(200000, common.copyConn, ants.WithNonblocking(false))
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
go func() {
|
go func() {
|
||||||
//m2 := NewMux(conn2, "tcp")
|
m2 := NewMux(conn2, "tcp")
|
||||||
m2 := NewMux(conn2, "kcp")
|
//m2 := NewMux(conn2, "kcp")
|
||||||
for {
|
for {
|
||||||
//logs.Warn("npc starting accept")
|
//logs.Warn("npc starting accept")
|
||||||
c, err := m2.Accept()
|
c, err := m2.Accept()
|
||||||
@ -84,8 +83,8 @@ func TestNewMux(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
//m1 := NewMux(conn1, "tcp")
|
m1 := NewMux(conn1, "tcp")
|
||||||
m1 := NewMux(conn1, "kcp")
|
//m1 := NewMux(conn1, "kcp")
|
||||||
l, err := net.Listen("tcp", "127.0.0.1:7777")
|
l, err := net.Listen("tcp", "127.0.0.1:7777")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Warn(err)
|
logs.Warn(err)
|
||||||
@ -147,14 +146,14 @@ func TestNewMux(t *testing.T) {
|
|||||||
|
|
||||||
func server() {
|
func server() {
|
||||||
var err error
|
var err error
|
||||||
//l, err := net.Listen("tcp", "127.0.0.1:9999")
|
l, err := net.Listen("tcp", "127.0.0.1:9999")
|
||||||
l, err := kcp.Listen("127.0.0.1:9999")
|
//l, err := kcp.Listen("127.0.0.1:9999")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Warn(err)
|
logs.Warn(err)
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
conn1, err = l.Accept()
|
conn1, err = l.Accept()
|
||||||
logs.Info("accept", conn1)
|
//logs.Info("accept", conn1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Warn(err)
|
logs.Warn(err)
|
||||||
}
|
}
|
||||||
@ -164,9 +163,9 @@ func server() {
|
|||||||
|
|
||||||
func client() {
|
func client() {
|
||||||
var err error
|
var err error
|
||||||
//conn2, err = net.Dial("tcp", "127.0.0.1:9999")
|
conn2, err = net.Dial("tcp", "127.0.0.1:9999")
|
||||||
logs.Warn("dial")
|
//logs.Warn("dial")
|
||||||
conn2, err = kcp.Dial("127.0.0.1:9999")
|
//conn2, err = kcp.Dial("127.0.0.1:9999")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Warn(err)
|
logs.Warn(err)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user