mirror of https://github.com/ehang-io/nps
perf test
parent
5f35415849
commit
5f58c34c8b
1
go.mod
1
go.mod
|
@ -12,6 +12,7 @@ require (
|
||||||
github.com/klauspost/cpuid v1.2.1 // indirect
|
github.com/klauspost/cpuid v1.2.1 // indirect
|
||||||
github.com/klauspost/reedsolomon v1.9.2 // indirect
|
github.com/klauspost/reedsolomon v1.9.2 // indirect
|
||||||
github.com/onsi/gomega v1.5.0 // indirect
|
github.com/onsi/gomega v1.5.0 // indirect
|
||||||
|
github.com/panjf2000/ants/v2 v2.2.2
|
||||||
github.com/pkg/errors v0.8.0
|
github.com/pkg/errors v0.8.0
|
||||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
|
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
|
||||||
github.com/shirou/gopsutil v2.18.12+incompatible
|
github.com/shirou/gopsutil v2.18.12+incompatible
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -44,6 +44,8 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/panjf2000/ants/v2 v2.2.2 h1:TWzusBjq/IflXhy+/S6u5wmMLCBdJnB9tPIx9Zmhvok=
|
||||||
|
github.com/panjf2000/ants/v2 v2.2.2/go.mod h1:1GFm8bV8nyCQvU5K4WvBCTG1/YBFOD2VzjffD8fV55A=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
|
|
@ -2,6 +2,8 @@ package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"github.com/panjf2000/ants/v2"
|
||||||
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -149,11 +151,62 @@ func (Self *muxPackagerPool) Put(pack *MuxPackager) {
|
||||||
Self.pool.Put(pack)
|
Self.pool.Put(pack)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type connGroup struct {
|
||||||
|
src net.Conn
|
||||||
|
dst net.Conn
|
||||||
|
wg *sync.WaitGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConnGroup(src net.Conn, dst net.Conn, wg *sync.WaitGroup) connGroup {
|
||||||
|
return connGroup{
|
||||||
|
src: src,
|
||||||
|
dst: dst,
|
||||||
|
wg: wg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyConnGroup(group interface{}) {
|
||||||
|
cg, ok := group.(connGroup)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err := CopyBuffer(cg.src, cg.dst)
|
||||||
|
if err != nil {
|
||||||
|
cg.src.Close()
|
||||||
|
cg.dst.Close()
|
||||||
|
//logs.Warn("close npc by copy from nps", err, c.connId)
|
||||||
|
}
|
||||||
|
cg.wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Conns struct {
|
||||||
|
conn1 net.Conn
|
||||||
|
conn2 net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConns(c1 net.Conn, c2 net.Conn) Conns {
|
||||||
|
return Conns{
|
||||||
|
conn1: c1,
|
||||||
|
conn2: c2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyConns(group interface{}) {
|
||||||
|
conns := group.(Conns)
|
||||||
|
wg := new(sync.WaitGroup)
|
||||||
|
wg.Add(2)
|
||||||
|
_ = connCopyPool.Invoke(newConnGroup(conns.conn1, conns.conn2, wg))
|
||||||
|
_ = connCopyPool.Invoke(newConnGroup(conns.conn2, conns.conn1, wg))
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
var once = sync.Once{}
|
var once = sync.Once{}
|
||||||
var BuffPool = bufferPool{}
|
var BuffPool = bufferPool{}
|
||||||
var CopyBuff = copyBufferPool{}
|
var CopyBuff = copyBufferPool{}
|
||||||
var MuxPack = muxPackagerPool{}
|
var MuxPack = muxPackagerPool{}
|
||||||
var WindowBuff = windowBufferPool{}
|
var WindowBuff = windowBufferPool{}
|
||||||
|
var connCopyPool, _ = ants.NewPoolWithFunc(200000, copyConnGroup, ants.WithNonblocking(false))
|
||||||
|
var CopyConnsPool, _ = ants.NewPoolWithFunc(100000, copyConns, ants.WithNonblocking(false))
|
||||||
|
|
||||||
func newPool() {
|
func newPool() {
|
||||||
BuffPool.New()
|
BuffPool.New()
|
||||||
|
|
|
@ -156,7 +156,7 @@ type ReceiveWindow struct {
|
||||||
bufQueue ReceiveWindowQueue
|
bufQueue ReceiveWindowQueue
|
||||||
element *ListElement
|
element *ListElement
|
||||||
readLength uint32
|
readLength uint32
|
||||||
readOp chan struct{}
|
//readOp chan struct{}
|
||||||
readWait bool
|
readWait bool
|
||||||
windowFull uint32
|
windowFull uint32
|
||||||
count int8
|
count int8
|
||||||
|
@ -167,7 +167,7 @@ type ReceiveWindow struct {
|
||||||
|
|
||||||
func (Self *ReceiveWindow) New(mux *Mux) {
|
func (Self *ReceiveWindow) New(mux *Mux) {
|
||||||
// initial a window for receive
|
// initial a window for receive
|
||||||
Self.readOp = make(chan struct{})
|
//Self.readOp = make(chan struct{})
|
||||||
Self.bufQueue.New()
|
Self.bufQueue.New()
|
||||||
//Self.bw = new(bandwidth)
|
//Self.bw = new(bandwidth)
|
||||||
Self.element = new(ListElement)
|
Self.element = new(ListElement)
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ type Mux struct {
|
||||||
connType string
|
connType string
|
||||||
writeQueue PriorityQueue
|
writeQueue PriorityQueue
|
||||||
//bufQueue BytesQueue
|
//bufQueue BytesQueue
|
||||||
sync.Mutex
|
//sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMux(c net.Conn, connType string) *Mux {
|
func NewMux(c net.Conn, connType string) *Mux {
|
||||||
|
@ -216,7 +215,7 @@ func (s *Mux) pingReturn() {
|
||||||
if latency < 0.5 && latency > 0 {
|
if latency < 0.5 && latency > 0 {
|
||||||
s.latency = latency
|
s.latency = latency
|
||||||
}
|
}
|
||||||
//logs.Warn("latency", s.latency)
|
logs.Warn("latency", s.latency)
|
||||||
common.WindowBuff.Put(data)
|
common.WindowBuff.Put(data)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -242,15 +241,19 @@ func (s *Mux) readSession() {
|
||||||
case common.MUX_NEW_CONN: //new connection
|
case common.MUX_NEW_CONN: //new connection
|
||||||
connection := NewConn(pack.Id, s, "npc ")
|
connection := NewConn(pack.Id, s, "npc ")
|
||||||
s.connMap.Set(pack.Id, connection) //it has been set before send ok
|
s.connMap.Set(pack.Id, connection) //it has been set before send ok
|
||||||
|
//go func(connection *conn) {
|
||||||
s.newConnCh <- connection
|
s.newConnCh <- connection
|
||||||
s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil)
|
s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil)
|
||||||
|
//}(connection)
|
||||||
continue
|
continue
|
||||||
case common.MUX_PING_FLAG: //ping
|
case common.MUX_PING_FLAG: //ping
|
||||||
s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, pack.Content)
|
s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, pack.Content)
|
||||||
common.WindowBuff.Put(pack.Content)
|
common.WindowBuff.Put(pack.Content)
|
||||||
continue
|
continue
|
||||||
case common.MUX_PING_RETURN:
|
case common.MUX_PING_RETURN:
|
||||||
|
//go func(content []byte) {
|
||||||
s.pingCh <- pack.Content
|
s.pingCh <- pack.Content
|
||||||
|
//}(pack.Content)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if connection, ok := s.connMap.Get(pack.Id); ok && !connection.isClose {
|
if connection, ok := s.connMap.Get(pack.Id); ok && !connection.isClose {
|
||||||
|
@ -275,8 +278,10 @@ func (s *Mux) readSession() {
|
||||||
continue
|
continue
|
||||||
case common.MUX_CONN_CLOSE: //close the connection
|
case common.MUX_CONN_CLOSE: //close the connection
|
||||||
s.connMap.Delete(pack.Id)
|
s.connMap.Delete(pack.Id)
|
||||||
|
//go func(connection *conn) {
|
||||||
connection.closeFlag = true
|
connection.closeFlag = true
|
||||||
connection.receiveWindow.Stop() // close signal to receive window
|
connection.receiveWindow.Stop() // close signal to receive window
|
||||||
|
//}(connection)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else if pack.Flag == common.MUX_CONN_CLOSE {
|
} else if pack.Flag == common.MUX_CONN_CLOSE {
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
@ -30,6 +29,7 @@ func TestNewMux(t *testing.T) {
|
||||||
logs.SetLogFuncCallDepth(3)
|
logs.SetLogFuncCallDepth(3)
|
||||||
server()
|
server()
|
||||||
client()
|
client()
|
||||||
|
//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")
|
||||||
|
@ -49,31 +49,34 @@ func TestNewMux(t *testing.T) {
|
||||||
}
|
}
|
||||||
//c2.(*net.TCPConn).SetReadBuffer(0)
|
//c2.(*net.TCPConn).SetReadBuffer(0)
|
||||||
//c2.(*net.TCPConn).SetReadBuffer(0)
|
//c2.(*net.TCPConn).SetReadBuffer(0)
|
||||||
go func(c2 net.Conn, c *conn) {
|
_ = common.CopyConnsPool.Invoke(common.NewConns(c2, c))
|
||||||
wg := sync.WaitGroup{}
|
//go func(c2 net.Conn, c *conn) {
|
||||||
wg.Add(1)
|
// wg := new(sync.WaitGroup)
|
||||||
go func() {
|
// wg.Add(2)
|
||||||
_, err = common.CopyBuffer(c2, c)
|
// _ = poolConnCopy.Invoke(common.newConnGroup(c2, c, wg))
|
||||||
if err != nil {
|
// //go func() {
|
||||||
c2.Close()
|
// // _, err = common.CopyBuffer(c2, c)
|
||||||
c.Close()
|
// // if err != nil {
|
||||||
//logs.Warn("close npc by copy from nps", err, c.connId)
|
// // c2.Close()
|
||||||
}
|
// // c.Close()
|
||||||
wg.Done()
|
// // //logs.Warn("close npc by copy from nps", err, c.connId)
|
||||||
}()
|
// // }
|
||||||
wg.Add(1)
|
// // wg.Done()
|
||||||
go func() {
|
// //}()
|
||||||
_, err = common.CopyBuffer(c, c2)
|
// //wg.Add(1)
|
||||||
if err != nil {
|
// _ = poolConnCopy.Invoke(common.newConnGroup(c, c2, wg))
|
||||||
c2.Close()
|
// //go func() {
|
||||||
c.Close()
|
// // _, err = common.CopyBuffer(c, c2)
|
||||||
//logs.Warn("close npc by copy from server", err, c.connId)
|
// // if err != nil {
|
||||||
}
|
// // c2.Close()
|
||||||
wg.Done()
|
// // c.Close()
|
||||||
}()
|
// // //logs.Warn("close npc by copy from server", err, c.connId)
|
||||||
//logs.Warn("npc wait")
|
// // }
|
||||||
wg.Wait()
|
// // wg.Done()
|
||||||
}(c2, c.(*conn))
|
// //}()
|
||||||
|
// //logs.Warn("npc wait")
|
||||||
|
// wg.Wait()
|
||||||
|
//}(c2, c.(*conn))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -99,23 +102,30 @@ func TestNewMux(t *testing.T) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
//logs.Warn("nps new conn success ", tmpCpnn.connId)
|
//logs.Warn("nps new conn success ", tmpCpnn.connId)
|
||||||
go func(tmpCpnn *conn, conns net.Conn) {
|
_ = common.CopyConnsPool.Invoke(common.NewConns(tmpCpnn, conns))
|
||||||
go func() {
|
//go func(tmpCpnn *conn, conns net.Conn) {
|
||||||
_, err := common.CopyBuffer(tmpCpnn, conns)
|
// wg := new(sync.WaitGroup)
|
||||||
if err != nil {
|
// wg.Add(2)
|
||||||
conns.Close()
|
// _ = poolConnCopy.Invoke(common.newConnGroup(tmpCpnn, conns, wg))
|
||||||
tmpCpnn.Close()
|
// //go func() {
|
||||||
//logs.Warn("close nps by copy from user", tmpCpnn.connId, err)
|
// // _, err := common.CopyBuffer(tmpCpnn, conns)
|
||||||
}
|
// // if err != nil {
|
||||||
}()
|
// // conns.Close()
|
||||||
//time.Sleep(time.Second)
|
// // tmpCpnn.Close()
|
||||||
_, err = common.CopyBuffer(conns, tmpCpnn)
|
// // //logs.Warn("close nps by copy from user", tmpCpnn.connId, err)
|
||||||
if err != nil {
|
// // }
|
||||||
conns.Close()
|
// //}()
|
||||||
tmpCpnn.Close()
|
// //wg.Add(1)
|
||||||
//logs.Warn("close nps by copy from npc ", tmpCpnn.connId, err)
|
// _ = poolConnCopy.Invoke(common.newConnGroup(conns, tmpCpnn, wg))
|
||||||
}
|
// //time.Sleep(time.Second)
|
||||||
}(tmpCpnn, conns)
|
// //_, err = common.CopyBuffer(conns, tmpCpnn)
|
||||||
|
// //if err != nil {
|
||||||
|
// // conns.Close()
|
||||||
|
// // tmpCpnn.Close()
|
||||||
|
// // //logs.Warn("close nps by copy from npc ", tmpCpnn.connId, err)
|
||||||
|
// //}
|
||||||
|
// wg.Wait()
|
||||||
|
//}(tmpCpnn, conns)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -180,7 +190,7 @@ Connection: keep-alive
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_raw(k int) {
|
func test_raw(k int) {
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 1; i++ {
|
||||||
ti := time.Now()
|
ti := time.Now()
|
||||||
conn, err := net.Dial("tcp", "127.0.0.1:7777")
|
conn, err := net.Dial("tcp", "127.0.0.1:7777")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -303,7 +313,7 @@ func TestFIFO(t *testing.T) {
|
||||||
d.New()
|
d.New()
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
for i := 0; i < 30010; i++ {
|
for i := 0; i < 300100; i++ {
|
||||||
data, err := d.Pop()
|
data, err := d.Pop()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
//fmt.Println(i, string(data.buf), err)
|
//fmt.Println(i, string(data.buf), err)
|
||||||
|
@ -318,17 +328,13 @@ func TestFIFO(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(time.Second * 10)
|
time.Sleep(time.Second * 10)
|
||||||
for i := 0; i < 3000; i++ {
|
for i := 0; i < 300000; i++ {
|
||||||
go func(i int) {
|
data := new(ListElement)
|
||||||
for n := 0; n < 10; n++ {
|
by := []byte("test " + strconv.Itoa(i) + " ") //
|
||||||
data := new(ListElement)
|
_ = data.New(by, uint16(len(by)), true)
|
||||||
by := []byte("test " + strconv.Itoa(i) + " " + strconv.Itoa(n)) //
|
//fmt.Println(string((*data).buf), data)
|
||||||
_ = data.New(by, uint16(len(by)), true)
|
//logs.Warn(string((*data).buf), data)
|
||||||
//fmt.Println(string((*data).buf), data)
|
d.Push(data)
|
||||||
//logs.Warn(string((*data).buf), data)
|
|
||||||
d.Push(data)
|
|
||||||
}
|
|
||||||
}(i)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
time.Sleep(time.Second * 100000)
|
time.Sleep(time.Second * 100000)
|
||||||
|
@ -345,7 +351,7 @@ func TestPriority(t *testing.T) {
|
||||||
d.New()
|
d.New()
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
for i := 0; i < 36005; i++ {
|
for i := 0; i < 360050; i++ {
|
||||||
data := d.Pop()
|
data := d.Pop()
|
||||||
//fmt.Println(i, string(data.buf), err)
|
//fmt.Println(i, string(data.buf), err)
|
||||||
logs.Warn(i, string(data.Content), data)
|
logs.Warn(i, string(data.Content), data)
|
||||||
|
@ -354,7 +360,7 @@ func TestPriority(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(time.Second * 10)
|
time.Sleep(time.Second * 10)
|
||||||
for i := 0; i < 3000; i++ {
|
for i := 0; i < 30000; i++ {
|
||||||
go func(i int) {
|
go func(i int) {
|
||||||
for n := 0; n < 10; n++ {
|
for n := 0; n < 10; n++ {
|
||||||
data := new(common.MuxPackager)
|
data := new(common.MuxPackager)
|
||||||
|
|
172
lib/mux/queue.go
172
lib/mux/queue.go
|
@ -1,52 +1,24 @@
|
||||||
package mux
|
package mux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/cnlh/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type QueueOp struct {
|
|
||||||
readOp chan struct{}
|
|
||||||
cleanOp chan struct{}
|
|
||||||
popWait uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Self *QueueOp) New() {
|
|
||||||
Self.readOp = make(chan struct{})
|
|
||||||
Self.cleanOp = make(chan struct{}, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Self *QueueOp) allowPop() (closed bool) {
|
|
||||||
if atomic.CompareAndSwapUint32(&Self.popWait, 1, 0) {
|
|
||||||
select {
|
|
||||||
case Self.readOp <- struct{}{}:
|
|
||||||
return false
|
|
||||||
case <-Self.cleanOp:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Self *QueueOp) Clean() {
|
|
||||||
Self.cleanOp <- struct{}{}
|
|
||||||
Self.cleanOp <- struct{}{}
|
|
||||||
close(Self.cleanOp)
|
|
||||||
}
|
|
||||||
|
|
||||||
type PriorityQueue struct {
|
type PriorityQueue struct {
|
||||||
QueueOp
|
|
||||||
highestChain *bufChain
|
highestChain *bufChain
|
||||||
middleChain *bufChain
|
middleChain *bufChain
|
||||||
lowestChain *bufChain
|
lowestChain *bufChain
|
||||||
starving uint8
|
starving uint8
|
||||||
|
stop bool
|
||||||
|
cond *sync.Cond
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *PriorityQueue) New() {
|
func (Self *PriorityQueue) New() {
|
||||||
|
@ -56,7 +28,8 @@ func (Self *PriorityQueue) New() {
|
||||||
Self.middleChain.new(32)
|
Self.middleChain.new(32)
|
||||||
Self.lowestChain = new(bufChain)
|
Self.lowestChain = new(bufChain)
|
||||||
Self.lowestChain.new(256)
|
Self.lowestChain.new(256)
|
||||||
Self.QueueOp.New()
|
locker := new(sync.Mutex)
|
||||||
|
Self.cond = sync.NewCond(locker)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *PriorityQueue) Push(packager *common.MuxPackager) {
|
func (Self *PriorityQueue) Push(packager *common.MuxPackager) {
|
||||||
|
@ -71,14 +44,44 @@ func (Self *PriorityQueue) Push(packager *common.MuxPackager) {
|
||||||
default:
|
default:
|
||||||
Self.lowestChain.pushHead(unsafe.Pointer(packager))
|
Self.lowestChain.pushHead(unsafe.Pointer(packager))
|
||||||
}
|
}
|
||||||
Self.allowPop()
|
//atomic.AddUint32(&Self.count, 1)
|
||||||
|
Self.cond.Signal()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxStarving uint8 = 8
|
const maxStarving uint8 = 8
|
||||||
|
|
||||||
func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) {
|
func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) {
|
||||||
startPop:
|
// PriorityQueue is empty, notice Push method
|
||||||
|
var iter bool
|
||||||
|
for {
|
||||||
|
packager = Self.pop()
|
||||||
|
if packager != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if Self.stop {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if iter {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
iter = true
|
||||||
|
runtime.Gosched()
|
||||||
|
}
|
||||||
|
Self.cond.L.Lock()
|
||||||
|
defer Self.cond.L.Unlock()
|
||||||
|
for packager = Self.pop(); packager == nil; {
|
||||||
|
if Self.stop {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Self.cond.Wait()
|
||||||
|
packager = Self.pop()
|
||||||
|
}
|
||||||
|
//atomic.AddUint32(&Self.count, ^uint32(0))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *PriorityQueue) pop() (packager *common.MuxPackager) {
|
||||||
ptr, ok := Self.highestChain.popTail()
|
ptr, ok := Self.highestChain.popTail()
|
||||||
if ok {
|
if ok {
|
||||||
packager = (*common.MuxPackager)(ptr)
|
packager = (*common.MuxPackager)(ptr)
|
||||||
|
@ -108,16 +111,12 @@ startPop:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// PriorityQueue is empty, notice Push method
|
return
|
||||||
if atomic.CompareAndSwapUint32(&Self.popWait, 0, 1) {
|
}
|
||||||
select {
|
|
||||||
case <-Self.readOp:
|
func (Self *PriorityQueue) Stop() {
|
||||||
goto startPop
|
Self.stop = true
|
||||||
case <-Self.cleanOp:
|
Self.cond.Broadcast()
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
goto startPop
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListElement struct {
|
type ListElement struct {
|
||||||
|
@ -137,18 +136,19 @@ func (Self *ListElement) New(buf []byte, l uint16, part bool) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReceiveWindowQueue struct {
|
type ReceiveWindowQueue struct {
|
||||||
QueueOp
|
|
||||||
chain *bufChain
|
chain *bufChain
|
||||||
length uint32
|
length uint32
|
||||||
stopOp chan struct{}
|
stopOp chan struct{}
|
||||||
|
readOp chan struct{}
|
||||||
|
popWait uint32
|
||||||
timeout time.Time
|
timeout time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *ReceiveWindowQueue) New() {
|
func (Self *ReceiveWindowQueue) New() {
|
||||||
Self.QueueOp.New()
|
Self.readOp = make(chan struct{})
|
||||||
Self.chain = new(bufChain)
|
Self.chain = new(bufChain)
|
||||||
Self.chain.new(64)
|
Self.chain.new(64)
|
||||||
Self.stopOp = make(chan struct{}, 1)
|
Self.stopOp = make(chan struct{}, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *ReceiveWindowQueue) Push(element *ListElement) {
|
func (Self *ReceiveWindowQueue) Push(element *ListElement) {
|
||||||
|
@ -158,15 +158,30 @@ func (Self *ReceiveWindowQueue) Push(element *ListElement) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *ReceiveWindowQueue) Pop() (element *ListElement, err error) {
|
func (Self *ReceiveWindowQueue) pop() (element *ListElement) {
|
||||||
startPop:
|
|
||||||
ptr, ok := Self.chain.popTail()
|
ptr, ok := Self.chain.popTail()
|
||||||
if ok {
|
if ok {
|
||||||
element = (*ListElement)(ptr)
|
element = (*ListElement)(ptr)
|
||||||
atomic.AddUint32(&Self.length, ^uint32(element.l-1))
|
atomic.AddUint32(&Self.length, ^uint32(element.l-1))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindowQueue) Pop() (element *ListElement, err error) {
|
||||||
|
var iter bool
|
||||||
|
startPop:
|
||||||
|
element = Self.pop()
|
||||||
|
if element != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !iter {
|
||||||
|
iter = true
|
||||||
|
runtime.Gosched()
|
||||||
|
goto startPop
|
||||||
|
}
|
||||||
if atomic.CompareAndSwapUint32(&Self.popWait, 0, 1) {
|
if atomic.CompareAndSwapUint32(&Self.popWait, 0, 1) {
|
||||||
|
iter = false
|
||||||
t := Self.timeout.Sub(time.Now())
|
t := Self.timeout.Sub(time.Now())
|
||||||
if t <= 0 {
|
if t <= 0 {
|
||||||
t = time.Minute
|
t = time.Minute
|
||||||
|
@ -176,8 +191,6 @@ startPop:
|
||||||
select {
|
select {
|
||||||
case <-Self.readOp:
|
case <-Self.readOp:
|
||||||
goto startPop
|
goto startPop
|
||||||
case <-Self.cleanOp:
|
|
||||||
return
|
|
||||||
case <-Self.stopOp:
|
case <-Self.stopOp:
|
||||||
err = io.EOF
|
err = io.EOF
|
||||||
return
|
return
|
||||||
|
@ -189,62 +202,31 @@ startPop:
|
||||||
goto startPop
|
goto startPop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindowQueue) allowPop() (closed bool) {
|
||||||
|
if atomic.CompareAndSwapUint32(&Self.popWait, 1, 0) {
|
||||||
|
select {
|
||||||
|
case Self.readOp <- struct{}{}:
|
||||||
|
return false
|
||||||
|
case <-Self.stopOp:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (Self *ReceiveWindowQueue) Len() (n uint32) {
|
func (Self *ReceiveWindowQueue) Len() (n uint32) {
|
||||||
return atomic.LoadUint32(&Self.length)
|
return atomic.LoadUint32(&Self.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *ReceiveWindowQueue) Stop() {
|
func (Self *ReceiveWindowQueue) Stop() {
|
||||||
Self.stopOp <- struct{}{}
|
Self.stopOp <- struct{}{}
|
||||||
|
Self.stopOp <- struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Self *ReceiveWindowQueue) SetTimeOut(t time.Time) {
|
func (Self *ReceiveWindowQueue) SetTimeOut(t time.Time) {
|
||||||
Self.timeout = t
|
Self.timeout = t
|
||||||
}
|
}
|
||||||
|
|
||||||
type BytesQueue struct {
|
|
||||||
QueueOp
|
|
||||||
chain *bufChain
|
|
||||||
stopOp chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Self *BytesQueue) New() {
|
|
||||||
Self.QueueOp.New()
|
|
||||||
Self.chain = new(bufChain)
|
|
||||||
Self.chain.new(8)
|
|
||||||
Self.stopOp = make(chan struct{}, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Self *BytesQueue) Push(buf *bytes.Buffer) {
|
|
||||||
Self.chain.pushHead(unsafe.Pointer(buf))
|
|
||||||
Self.allowPop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Self *BytesQueue) Pop() (buf *bytes.Buffer, err error) {
|
|
||||||
startPop:
|
|
||||||
ptr, ok := Self.chain.popTail()
|
|
||||||
if ok {
|
|
||||||
buf = (*bytes.Buffer)(ptr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if atomic.CompareAndSwapUint32(&Self.popWait, 0, 1) {
|
|
||||||
select {
|
|
||||||
case <-Self.readOp:
|
|
||||||
goto startPop
|
|
||||||
case <-Self.cleanOp:
|
|
||||||
return
|
|
||||||
case <-Self.stopOp:
|
|
||||||
err = io.EOF
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
goto startPop
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Self *BytesQueue) Stop() {
|
|
||||||
Self.stopOp <- struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://golang.org/src/sync/poolqueue.go
|
// https://golang.org/src/sync/poolqueue.go
|
||||||
|
|
||||||
type bufDequeue struct {
|
type bufDequeue struct {
|
||||||
|
|
Loading…
Reference in New Issue