mirror of
https://gitee.com/WuKongDev/WuKongIM.git
synced 2025-12-06 06:49:06 +08:00
fix: Potential deadlock
This commit is contained in:
@@ -73,8 +73,12 @@ func (co *ConnzAPI) HandleConnz(c *wkhttp.Context) {
|
||||
sortOpt = SortOpt(sortStr)
|
||||
}
|
||||
var connInfos []*ConnInfo
|
||||
|
||||
fmt.Println("getConnInfos....start.")
|
||||
resultConns := co.s.GetConnInfos(uid, sortOpt, offset, limit)
|
||||
connInfos = make([]*ConnInfo, 0, len(resultConns))
|
||||
|
||||
fmt.Println("getConnInfos....start---2.")
|
||||
for _, resultConn := range resultConns {
|
||||
|
||||
connInfo := newConnInfo(resultConn)
|
||||
@@ -94,6 +98,8 @@ func (co *ConnzAPI) HandleConnz(c *wkhttp.Context) {
|
||||
connInfos = append(connInfos, connInfo)
|
||||
}
|
||||
|
||||
fmt.Println("getConnInfos....end.")
|
||||
|
||||
c.JSON(http.StatusOK, Connz{
|
||||
Connections: connInfos,
|
||||
Now: time.Now(),
|
||||
@@ -105,11 +111,15 @@ func (co *ConnzAPI) HandleConnz(c *wkhttp.Context) {
|
||||
|
||||
func (s *Server) GetConnInfos(uid string, sortOpt SortOpt, offset, limit int) []*connContext {
|
||||
connCtxs := make([]*connContext, 0, s.engine.ConnCount())
|
||||
|
||||
fmt.Println("Iterator.....", s.engine.ConnCount())
|
||||
|
||||
s.engine.Iterator(func(c wknet.Conn) bool {
|
||||
if c.Context() == nil { // 没有上下文的连接不处理
|
||||
ctx := c.Context()
|
||||
if ctx == nil { // 没有上下文的连接不处理
|
||||
return true
|
||||
}
|
||||
connCtx := c.Context().(*connContext)
|
||||
connCtx := ctx.(*connContext)
|
||||
if strings.TrimSpace(uid) != "" {
|
||||
if strings.Contains(connCtx.uid, uid) {
|
||||
connCtxs = append(connCtxs, connCtx)
|
||||
@@ -119,6 +129,7 @@ func (s *Server) GetConnInfos(uid string, sortOpt SortOpt, offset, limit int) []
|
||||
}
|
||||
return true
|
||||
})
|
||||
fmt.Println("Iterator.222....")
|
||||
|
||||
switch sortOpt {
|
||||
case ByID:
|
||||
|
||||
@@ -374,6 +374,7 @@ func (r *channelReactor) requestChannelFoward(nodeId uint64, req ChannelFowardRe
|
||||
}
|
||||
resp, err := r.s.cluster.RequestWithContext(timeoutCtx, nodeId, "/wk/channelFoward", data)
|
||||
if err != nil {
|
||||
r.Error("requestChannelFoward unkown error", zap.Error(err), zap.Uint64("nodeId", nodeId))
|
||||
return false, err
|
||||
}
|
||||
if resp.Status == proto.Status(errCodeNotIsChannelLeader) { // 转发下去的节点不是频道领导,这时候要重新获取下领导节点
|
||||
|
||||
@@ -64,7 +64,7 @@ func (m *channelMsgQueue) shrinkMessagesArray() {
|
||||
const lenMultiple = 2
|
||||
if len(m.messages) == 0 {
|
||||
m.messages = nil
|
||||
} else if len(m.messages)*lenMultiple < cap(m.messages) {
|
||||
} else if cap(m.messages) >= len(m.messages)*lenMultiple {
|
||||
newMessages := make([]ReactorChannelMessage, len(m.messages))
|
||||
copy(newMessages, m.messages)
|
||||
m.messages = newMessages
|
||||
|
||||
@@ -811,7 +811,8 @@ func (o *Options) ConfigureWithViper(vp *viper.Viper) {
|
||||
o.DeadlockCheck = o.getBool("deadlockCheck", o.DeadlockCheck)
|
||||
|
||||
// =================== other ===================
|
||||
deadlock.Opts.Disable = !o.DeadlockCheck
|
||||
// deadlock.Opts.Disable = !o.DeadlockCheck
|
||||
deadlock.Opts.Disable = false
|
||||
o.PprofOn = o.getBool("pprofOn", o.PprofOn)
|
||||
o.OldV1Api = o.getString("oldV1Api", o.OldV1Api)
|
||||
o.MigrateStartStep = MigrateStep(o.getString("migrateStartStep", string(o.MigrateStartStep)))
|
||||
|
||||
@@ -76,7 +76,6 @@ func newUserHandler(uid string, sub *userReactorSub) *userHandler {
|
||||
initTick: opts.Reactor.User.ProcessIntervalTick,
|
||||
}
|
||||
|
||||
u.Info("new user handler")
|
||||
return u
|
||||
}
|
||||
|
||||
@@ -121,7 +120,7 @@ func (u *userHandler) ready() userReady {
|
||||
u.authing = true
|
||||
msgs := u.authQueue.sliceWithSize(u.authQueue.processingIndex+1, u.authQueue.lastIndex+1, 0)
|
||||
u.actions = append(u.actions, UserAction{UniqueNo: u.uniqueNo, ActionType: UserActionAuth, Messages: msgs})
|
||||
u.Info("send auth...")
|
||||
u.Debug("send auth...")
|
||||
}
|
||||
// 发送ping
|
||||
if u.hasPing() {
|
||||
@@ -171,7 +170,7 @@ func (u *userHandler) ready() userReady {
|
||||
Messages: msgs,
|
||||
},
|
||||
})
|
||||
u.Info("forward auth...")
|
||||
u.Debug("forward auth...")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func (u *userHandler) step(a UserAction) error {
|
||||
case UserActionConnect: // 连接
|
||||
for _, msg := range a.Messages {
|
||||
msg.Index = u.authQueue.lastIndex + 1
|
||||
u.Info("add auth message...", zap.Uint64("index", msg.Index))
|
||||
u.Debug("add auth message...", zap.Uint64("index", msg.Index))
|
||||
u.authQueue.appendMessage(msg)
|
||||
}
|
||||
|
||||
|
||||
2
main.go
2
main.go
@@ -36,7 +36,7 @@ func main() {
|
||||
// log.Println("服务启动出错", "打开异常日志文件失败", err)
|
||||
// return
|
||||
// }
|
||||
// 将进程标准出错重定向至文件,进程崩溃时运行时将向该文件记录协程调用栈信息
|
||||
// // 将进程标准出错重定向至文件,进程崩溃时运行时将向该文件记录协程调用栈信息
|
||||
// syscall.Dup2(int(logFile.Fd()), int(os.Stderr.Fd()))
|
||||
|
||||
undo, err := maxprocs.Set()
|
||||
|
||||
@@ -294,3 +294,20 @@ func DecodeNodeJoined(data []byte) (uint64, []*pb.Slot, error) {
|
||||
}
|
||||
return nodeId, slots, nil
|
||||
}
|
||||
|
||||
func EncodeLeaderChange(leaderId uint64) ([]byte, error) {
|
||||
enc := wkproto.NewEncoder()
|
||||
defer enc.End()
|
||||
enc.WriteUint64(leaderId)
|
||||
return enc.Bytes(), nil
|
||||
}
|
||||
|
||||
func DecodeLeaderChange(data []byte) (uint64, error) {
|
||||
dec := wkproto.NewDecoder(data)
|
||||
var err error
|
||||
var leaderId uint64
|
||||
if leaderId, err = dec.Uint64(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return leaderId, nil
|
||||
}
|
||||
|
||||
@@ -176,6 +176,10 @@ func (h *handler) getLogs(startLogIndex uint64, endLogIndex uint64) ([]replica.L
|
||||
func (h *handler) SetHardState(hd replica.HardState) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
if hd.LeaderId != h.leaderId {
|
||||
h.Info("config leader change", zap.Uint64("oldLeader", h.leaderId), zap.Uint64("newLeader", hd.LeaderId))
|
||||
}
|
||||
h.leaderId = hd.LeaderId
|
||||
|
||||
}
|
||||
|
||||
@@ -170,6 +170,10 @@ func (c *channel) AppliedIndex() (uint64, error) {
|
||||
|
||||
func (c *channel) SetHardState(hd replica.HardState) {
|
||||
|
||||
if hd.LeaderId != c.cfg.LeaderId {
|
||||
c.Info("channel leader change", zap.Uint64("oldLeader", c.cfg.LeaderId), zap.Uint64("newLeader", hd.LeaderId))
|
||||
}
|
||||
|
||||
// if hd.LeaderId == 0 {
|
||||
// return
|
||||
// }
|
||||
|
||||
@@ -184,7 +184,11 @@ func (s *slot) AppliedIndex() (uint64, error) {
|
||||
}
|
||||
|
||||
func (s *slot) SetHardState(hd replica.HardState) {
|
||||
if hd.LeaderId != s.leaderId.Load() {
|
||||
s.Info("slot leader change", zap.Uint64("oldLeader", s.leaderId.Load()), zap.Uint64("newLeader", hd.LeaderId))
|
||||
}
|
||||
s.leaderId.Store(hd.LeaderId)
|
||||
|
||||
}
|
||||
|
||||
func (s *slot) Tick() {
|
||||
|
||||
@@ -6,12 +6,12 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/RussellLuo/timingwheel"
|
||||
"github.com/WuKongIM/WuKongIM/pkg/ring"
|
||||
wkproto "github.com/WuKongIM/WuKongIMGoProto"
|
||||
"github.com/WuKongIM/crypto/tls"
|
||||
"github.com/sasha-s/go-deadlock"
|
||||
|
||||
@@ -46,20 +46,20 @@ type Conn interface {
|
||||
UID() string
|
||||
// SetUID sets the user uid.
|
||||
SetUID(uid string)
|
||||
DeviceLevel() uint8
|
||||
SetDeviceLevel(deviceLevel uint8)
|
||||
// DeviceLevel() uint8
|
||||
// SetDeviceLevel(deviceLevel uint8)
|
||||
// DeviceFlag returns the device flag.
|
||||
DeviceFlag() uint8
|
||||
// DeviceFlag() uint8
|
||||
// SetDeviceFlag sets the device flag.
|
||||
SetDeviceFlag(deviceFlag uint8)
|
||||
// SetDeviceFlag(deviceFlag uint8)
|
||||
// DeviceID returns the device id.
|
||||
DeviceID() string
|
||||
// DeviceID() string
|
||||
// SetValue sets the value associated with key to value.
|
||||
SetValue(key string, value interface{})
|
||||
// Value returns the value associated with key.
|
||||
Value(key string) interface{}
|
||||
// SetDeviceID sets the device id.
|
||||
SetDeviceID(deviceID string)
|
||||
// SetDeviceID(deviceID string)
|
||||
// Flush flushes the data to the connection.
|
||||
Flush() error
|
||||
// Read reads the data from the connection.
|
||||
@@ -97,10 +97,6 @@ type Conn interface {
|
||||
IsAuthed() bool
|
||||
// SetAuthed sets the connection is authed.
|
||||
SetAuthed(authed bool)
|
||||
// ProtoVersion get message proto version
|
||||
ProtoVersion() int
|
||||
// SetProtoVersion sets message proto version
|
||||
SetProtoVersion(version int)
|
||||
// LastActivity returns the last activity time.
|
||||
LastActivity() time.Time
|
||||
// Uptime returns the connection uptime.
|
||||
@@ -117,7 +113,7 @@ type Conn interface {
|
||||
SetWriteDeadline(t time.Time) error
|
||||
|
||||
// ConnStats returns the connection stats.
|
||||
ConnStats() *ConnStats
|
||||
// ConnStats() *ConnStats
|
||||
}
|
||||
|
||||
type IWSConn interface {
|
||||
@@ -135,46 +131,38 @@ type DefaultConn struct {
|
||||
closed atomic.Bool // if the connection is closed
|
||||
isWAdded bool // if the connection is added to the write event
|
||||
mu deadlock.RWMutex
|
||||
context interface{}
|
||||
authed bool // if the connection is authed
|
||||
protoVersion int
|
||||
id int64
|
||||
uid string
|
||||
deviceFlag uint8
|
||||
deviceLevel uint8
|
||||
deviceID string
|
||||
valueMap map[string]interface{}
|
||||
context atomic.Value
|
||||
authed atomic.Bool // if the connection is authed
|
||||
id atomic.Int64
|
||||
uid atomic.String
|
||||
valueMap sync.Map
|
||||
|
||||
uptime time.Time
|
||||
lastActivity time.Time
|
||||
maxIdle time.Duration
|
||||
idleTimer *timingwheel.Timer
|
||||
uptime atomic.Time
|
||||
lastActivity atomic.Time
|
||||
maxIdle atomic.Duration
|
||||
|
||||
connStats *ConnStats
|
||||
idleTimer *timingwheel.Timer
|
||||
|
||||
wklog.Log
|
||||
}
|
||||
|
||||
func GetDefaultConn(id int64, connFd NetFd, localAddr, remoteAddr net.Addr, eg *Engine, reactorSub *ReactorSub) *DefaultConn {
|
||||
defaultConn := eg.defaultConnPool.Get().(*DefaultConn)
|
||||
defaultConn.id = id
|
||||
defaultConn.id.Store(id)
|
||||
defaultConn.fd = connFd
|
||||
defaultConn.remoteAddr = remoteAddr
|
||||
defaultConn.localAddr = localAddr
|
||||
defaultConn.isWAdded = false
|
||||
defaultConn.authed = false
|
||||
defaultConn.authed.Store(false)
|
||||
defaultConn.closed.Store(false)
|
||||
defaultConn.uid = ""
|
||||
defaultConn.deviceFlag = 0
|
||||
defaultConn.deviceLevel = 0
|
||||
defaultConn.uid.Store("")
|
||||
defaultConn.eg = eg
|
||||
defaultConn.reactorSub = reactorSub
|
||||
defaultConn.valueMap = map[string]interface{}{}
|
||||
defaultConn.context = nil
|
||||
defaultConn.lastActivity = time.Now()
|
||||
defaultConn.uptime = time.Now()
|
||||
defaultConn.valueMap = sync.Map{}
|
||||
defaultConn.context.Store(nil)
|
||||
defaultConn.lastActivity.Store(time.Now())
|
||||
defaultConn.uptime.Store(time.Now())
|
||||
defaultConn.Log = wklog.NewWKLog(fmt.Sprintf("Conn[[reactor-%d]%d]", reactorSub.idx, id))
|
||||
defaultConn.connStats = NewConnStats()
|
||||
|
||||
defaultConn.inboundBuffer = eg.eventHandler.OnNewInboundConn(defaultConn, eg)
|
||||
defaultConn.outboundBuffer = eg.eventHandler.OnNewOutboundConn(defaultConn, eg)
|
||||
@@ -208,15 +196,11 @@ func CreateConn(id int64, connFd NetFd, localAddr, remoteAddr net.Addr, eg *Engi
|
||||
}
|
||||
|
||||
func (d *DefaultConn) ID() int64 {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
return d.id
|
||||
return d.id.Load()
|
||||
}
|
||||
|
||||
func (d *DefaultConn) SetID(id int64) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.id = id
|
||||
d.id.Store(id)
|
||||
}
|
||||
|
||||
func (d *DefaultConn) ReadToInboundBuffer() (int, error) {
|
||||
@@ -237,9 +221,7 @@ func (d *DefaultConn) ReadToInboundBuffer() (int, error) {
|
||||
}
|
||||
|
||||
func (d *DefaultConn) KeepLastActivity() {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.lastActivity = time.Now()
|
||||
d.lastActivity.Store(time.Now())
|
||||
}
|
||||
|
||||
func (d *DefaultConn) Read(buf []byte) (int, error) {
|
||||
@@ -307,7 +289,7 @@ func (d *DefaultConn) Fd() NetFd {
|
||||
}
|
||||
|
||||
// 调用次方法需要加锁
|
||||
func (d *DefaultConn) closeNeedLock(closeErr error) error {
|
||||
func (d *DefaultConn) close(closeErr error) error {
|
||||
|
||||
if d.closed.Load() {
|
||||
return nil
|
||||
@@ -317,16 +299,14 @@ func (d *DefaultConn) closeNeedLock(closeErr error) error {
|
||||
if closeErr != nil && !errors.Is(closeErr, syscall.ECONNRESET) { // ECONNRESET表示fd已经关闭,不需要再次关闭
|
||||
err := d.reactorSub.DeleteFd(d) // 先删除fd
|
||||
if err != nil {
|
||||
d.Debug("delete fd from poller error", zap.Error(err), zap.Int("fd", d.Fd().fd), zap.String("uid", d.uid), zap.String("deviceID", d.deviceID))
|
||||
d.Debug("delete fd from poller error", zap.Error(err), zap.Int("fd", d.Fd().fd), zap.String("uid", d.uid.Load()))
|
||||
}
|
||||
}
|
||||
|
||||
_ = d.fd.Close() // 后关闭fd
|
||||
d.eg.RemoveConn(d) // remove from the engine
|
||||
d.reactorSub.ConnDec() // decrease the connection count
|
||||
d.mu.Unlock() // 这里先解锁,避免OnClose中调用conn的方法导致死锁
|
||||
d.eg.eventHandler.OnClose(d) // call the close handler
|
||||
d.mu.Lock()
|
||||
|
||||
d.release()
|
||||
|
||||
@@ -334,16 +314,12 @@ func (d *DefaultConn) closeNeedLock(closeErr error) error {
|
||||
}
|
||||
|
||||
func (d *DefaultConn) Close() error {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
return d.closeNeedLock(nil)
|
||||
return d.close(nil)
|
||||
}
|
||||
|
||||
func (d *DefaultConn) CloseWithErr(err error) error {
|
||||
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
return d.closeNeedLock(err)
|
||||
return d.close(err)
|
||||
}
|
||||
|
||||
func (d *DefaultConn) RemoteAddr() net.Addr {
|
||||
@@ -376,20 +352,20 @@ func (d *DefaultConn) SetWriteDeadline(t time.Time) error {
|
||||
|
||||
func (d *DefaultConn) release() {
|
||||
|
||||
d.Debug("release connection", zap.String("uid", d.uid), zap.String("deviceID", d.deviceID))
|
||||
d.Debug("release connection")
|
||||
d.fd = NetFd{}
|
||||
d.maxIdle = 0
|
||||
d.maxIdle = *atomic.NewDuration(0)
|
||||
if d.idleTimer != nil {
|
||||
d.idleTimer.Stop()
|
||||
d.idleTimer = nil
|
||||
}
|
||||
err := d.inboundBuffer.Release()
|
||||
if err != nil {
|
||||
d.Debug("inboundBuffer release error", zap.Error(err), zap.String("uid", d.uid), zap.String("deviceID", d.deviceID))
|
||||
d.Debug("inboundBuffer release error", zap.Error(err))
|
||||
}
|
||||
err = d.outboundBuffer.Release()
|
||||
if err != nil {
|
||||
d.Debug("outboundBuffer release error", zap.Error(err), zap.String("uid", d.uid), zap.String("deviceID", d.deviceID))
|
||||
d.Debug("outboundBuffer release error", zap.Error(err))
|
||||
}
|
||||
|
||||
d.eg.defaultConnPool.Put(d)
|
||||
@@ -427,93 +403,33 @@ func (d *DefaultConn) ReactorSub() *ReactorSub {
|
||||
}
|
||||
|
||||
func (d *DefaultConn) SetContext(ctx interface{}) {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
d.context = ctx
|
||||
d.context.Store(ctx)
|
||||
}
|
||||
func (d *DefaultConn) Context() interface{} {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
return d.context
|
||||
return d.context.Load()
|
||||
}
|
||||
|
||||
func (d *DefaultConn) IsAuthed() bool {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
return d.authed
|
||||
return d.authed.Load()
|
||||
}
|
||||
func (d *DefaultConn) SetAuthed(authed bool) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.authed = authed
|
||||
}
|
||||
|
||||
func (d *DefaultConn) ProtoVersion() int {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
return d.protoVersion
|
||||
}
|
||||
func (d *DefaultConn) SetProtoVersion(version int) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.protoVersion = version
|
||||
d.authed.Store(authed)
|
||||
}
|
||||
|
||||
func (d *DefaultConn) UID() string {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
return d.uid
|
||||
return d.uid.Load()
|
||||
}
|
||||
func (d *DefaultConn) SetUID(uid string) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.uid = uid
|
||||
}
|
||||
|
||||
func (d *DefaultConn) DeviceFlag() uint8 {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
return d.deviceFlag
|
||||
}
|
||||
|
||||
func (d *DefaultConn) SetDeviceFlag(deviceFlag uint8) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.deviceFlag = deviceFlag
|
||||
}
|
||||
|
||||
func (d *DefaultConn) DeviceLevel() uint8 {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
return d.deviceLevel
|
||||
}
|
||||
|
||||
func (d *DefaultConn) SetDeviceLevel(deviceLevel uint8) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.deviceLevel = deviceLevel
|
||||
}
|
||||
|
||||
func (d *DefaultConn) DeviceID() string {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
return d.deviceID
|
||||
}
|
||||
func (d *DefaultConn) SetDeviceID(deviceID string) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.deviceID = deviceID
|
||||
d.uid.Store(uid)
|
||||
}
|
||||
|
||||
func (d *DefaultConn) SetValue(key string, value interface{}) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.valueMap[key] = value
|
||||
d.valueMap.Store(key, value)
|
||||
}
|
||||
func (d *DefaultConn) Value(key string) interface{} {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
return d.valueMap[key]
|
||||
|
||||
value, _ := d.valueMap.Load(key)
|
||||
return value
|
||||
}
|
||||
|
||||
func (d *DefaultConn) InboundBuffer() InboundBuffer {
|
||||
@@ -525,26 +441,20 @@ func (d *DefaultConn) OutboundBuffer() OutboundBuffer {
|
||||
}
|
||||
|
||||
func (d *DefaultConn) LastActivity() time.Time {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
return d.lastActivity
|
||||
return d.lastActivity.Load()
|
||||
}
|
||||
|
||||
func (d *DefaultConn) Uptime() time.Time {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
return d.uptime
|
||||
return d.uptime.Load()
|
||||
}
|
||||
|
||||
func (d *DefaultConn) SetMaxIdle(maxIdle time.Duration) {
|
||||
if d.closed.Load() {
|
||||
d.Debug("connection is closed, setMaxIdle failed", zap.String("uid", d.uid), zap.String("deviceID", d.deviceID))
|
||||
d.Debug("connection is closed, setMaxIdle failed")
|
||||
return
|
||||
}
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
d.maxIdle = maxIdle
|
||||
d.maxIdle.Store(maxIdle)
|
||||
|
||||
if d.idleTimer != nil {
|
||||
d.idleTimer.Stop()
|
||||
@@ -552,30 +462,22 @@ func (d *DefaultConn) SetMaxIdle(maxIdle time.Duration) {
|
||||
|
||||
if maxIdle > 0 {
|
||||
d.idleTimer = d.eg.Schedule(maxIdle/2, func() {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.lastActivity.Add(maxIdle).After(time.Now()) {
|
||||
if d.lastActivity.Load().Add(maxIdle).After(time.Now()) {
|
||||
return
|
||||
}
|
||||
d.Debug("max idle time exceeded, close the connection", zap.Duration("maxIdle", maxIdle), zap.Duration("lastActivity", time.Since(d.lastActivity)), zap.String("conn", d.String()))
|
||||
d.Debug("max idle time exceeded, close the connection", zap.Duration("maxIdle", maxIdle), zap.Duration("lastActivity", time.Since(d.lastActivity.Load())), zap.String("conn", d.String()))
|
||||
if d.idleTimer != nil {
|
||||
d.idleTimer.Stop()
|
||||
}
|
||||
if d.closed.Load() {
|
||||
return
|
||||
}
|
||||
d.closeNeedLock(nil)
|
||||
_ = d.close(nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DefaultConn) ConnStats() *ConnStats {
|
||||
return d.connStats
|
||||
}
|
||||
|
||||
func (d *DefaultConn) flush() error {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if d.closed.Load() {
|
||||
return net.ErrClosed
|
||||
@@ -599,14 +501,12 @@ func (d *DefaultConn) flush() error {
|
||||
switch err {
|
||||
case nil:
|
||||
case syscall.EAGAIN:
|
||||
d.Error("write error", zap.Error(err), zap.String("uid", d.uid), zap.String("deviceID", d.deviceID))
|
||||
d.Error("write error", zap.Error(err))
|
||||
default:
|
||||
// d.reactorSub.CloseConn 里使用了d.mu的锁,所以这里先要解锁,调用完后再锁上
|
||||
d.mu.Unlock()
|
||||
err = d.reactorSub.CloseConn(d, os.NewSyscallError("write", err))
|
||||
d.mu.Lock()
|
||||
if err != nil {
|
||||
d.Error("failed to close conn", zap.Error(err), zap.String("uid", d.uid), zap.String("deviceID", d.deviceID))
|
||||
d.Error("failed to close conn", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -696,7 +596,7 @@ func (d *DefaultConn) overflowForInbound(n int) bool {
|
||||
|
||||
func (d *DefaultConn) String() string {
|
||||
|
||||
return fmt.Sprintf("Conn[%d] uid=%s fd=%d deviceFlag=%s deviceLevel=%s deviceID=%s", d.id, d.uid, d.fd, wkproto.DeviceFlag(d.deviceFlag), wkproto.DeviceLevel(d.deviceLevel), d.deviceID)
|
||||
return fmt.Sprintf("Conn[%d] fd=%d", d.id.Load(), d.fd)
|
||||
}
|
||||
|
||||
type TLSConn struct {
|
||||
@@ -830,29 +730,6 @@ func (t *TLSConn) WakeWrite() error {
|
||||
return t.d.WakeWrite()
|
||||
}
|
||||
|
||||
func (t *TLSConn) DeviceFlag() uint8 {
|
||||
return t.d.DeviceFlag()
|
||||
}
|
||||
|
||||
func (t *TLSConn) SetDeviceFlag(flag uint8) {
|
||||
t.d.SetDeviceFlag(flag)
|
||||
}
|
||||
|
||||
func (t *TLSConn) DeviceLevel() uint8 {
|
||||
return t.d.DeviceLevel()
|
||||
}
|
||||
|
||||
func (t *TLSConn) SetDeviceLevel(level uint8) {
|
||||
t.d.SetDeviceLevel(level)
|
||||
}
|
||||
|
||||
func (t *TLSConn) DeviceID() string {
|
||||
return t.d.DeviceID()
|
||||
}
|
||||
func (t *TLSConn) SetDeviceID(id string) {
|
||||
t.d.deviceID = id
|
||||
}
|
||||
|
||||
func (t *TLSConn) Discard(n int) (int, error) {
|
||||
return t.d.Discard(n)
|
||||
}
|
||||
@@ -885,14 +762,6 @@ func (t *TLSConn) Peek(n int) ([]byte, error) {
|
||||
return t.d.Peek(n)
|
||||
}
|
||||
|
||||
func (t *TLSConn) ProtoVersion() int {
|
||||
return t.d.ProtoVersion()
|
||||
}
|
||||
|
||||
func (t *TLSConn) SetProtoVersion(version int) {
|
||||
t.d.SetProtoVersion(version)
|
||||
}
|
||||
|
||||
func (t *TLSConn) ReactorSub() *ReactorSub {
|
||||
return t.d.ReactorSub()
|
||||
}
|
||||
@@ -921,10 +790,6 @@ func (t *TLSConn) SetMaxIdle(maxIdle time.Duration) {
|
||||
t.d.SetMaxIdle(maxIdle)
|
||||
}
|
||||
|
||||
func (t *TLSConn) ConnStats() *ConnStats {
|
||||
return t.d.connStats
|
||||
}
|
||||
|
||||
func (t *TLSConn) String() string {
|
||||
return t.d.String()
|
||||
}
|
||||
@@ -990,6 +855,7 @@ func newConnMatrix() *connMatrix {
|
||||
}
|
||||
|
||||
func (cm *connMatrix) iterate(f func(Conn) bool) {
|
||||
fmt.Println("cm.conns---->", len(cm.conns))
|
||||
for _, c := range cm.conns {
|
||||
if c != nil {
|
||||
if !f(c) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
stls "github.com/WuKongIM/crypto/tls"
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -18,24 +19,24 @@ import (
|
||||
func TestConn(t *testing.T) {
|
||||
conns := make([]*DefaultConn, 0)
|
||||
conns = append(conns, &DefaultConn{
|
||||
id: 1,
|
||||
uid: "1",
|
||||
id: *atomic.NewInt64(1),
|
||||
uid: *atomic.NewString("1"),
|
||||
fd: NetFd{fd: 1},
|
||||
}, &DefaultConn{
|
||||
id: 2,
|
||||
uid: "2",
|
||||
id: *atomic.NewInt64(2),
|
||||
uid: *atomic.NewString("2"),
|
||||
fd: NetFd{fd: 2},
|
||||
}, &DefaultConn{
|
||||
id: 3,
|
||||
uid: "3",
|
||||
id: *atomic.NewInt64(3),
|
||||
uid: *atomic.NewString("3"),
|
||||
fd: NetFd{fd: 3},
|
||||
}, &DefaultConn{
|
||||
id: 4,
|
||||
uid: "4",
|
||||
id: *atomic.NewInt64(4),
|
||||
uid: *atomic.NewString("4"),
|
||||
fd: NetFd{fd: 4},
|
||||
}, &DefaultConn{
|
||||
id: 5,
|
||||
uid: "5",
|
||||
id: *atomic.NewInt64(5),
|
||||
uid: *atomic.NewString("5"),
|
||||
fd: NetFd{fd: 5},
|
||||
},
|
||||
)
|
||||
|
||||
@@ -400,7 +400,7 @@ func (c *Client) RequestWithContext(ctx context.Context, p string, body []byte)
|
||||
}
|
||||
return x.(*proto.Response), nil
|
||||
case <-timeoutCtx.Done():
|
||||
timeoutCtx.Deadline()
|
||||
c.Error("request timeout", zap.String("path", p), zap.String("id", c.opts.UID), zap.Error(timeoutCtx.Err()))
|
||||
return nil, timeoutCtx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user