Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the socket read/write fatal deadlock problem when a large number of concurrent requests or a large amount of data is written at the same time #572

Open
wants to merge 2 commits into
base: v2-unstable
Choose a base branch
from

Conversation

snower
Copy link

@snower snower commented Mar 13, 2021

When a large number of concurrent requests or a large amount of data is written at the same time, the connection send buffer may be exceeded or the database processing speed may be exceeded, and the data not completely written will be discarded, which will lead to deadlock due to incomplete connection transfer protocol data.

The connection state management and connection write data are completely separate, and the connection state is not changed when writing data, so the write data should be released with an independent lock and the state management lock, otherwise it may lead to read results that cannot get the state lock to read the results, and then further lead to deadlock when the connection write data cannot be completed.

Testing Code

// main
package main

import (
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"sync"
	"time"
)

var count = 0
var wait = make(chan int64)
var lock = sync.Mutex{}

type MgoLog struct {
}

func (self MgoLog) Output(i int, msg string) error {
	fmt.Println(i, " ", msg)
	return nil
}

func test(session *mgo.Session, index int) {
	start_time := time.Now().Unix()
	weixin := make(map[string]interface{})
	c := session.DB("test").C("test").Find(bson.M{})
	c.One(weixin)

	lock.Lock()
	defer lock.Unlock()
	count += 1
	t := time.Now().Unix() - start_time
	fmt.Println(t, " ", index, " ", count)
	if count >= 100000 {
		wait <- t
	}
}

func main() {
	mgo.SetLogger(MgoLog{})
	session, err := mgo.Dial("172.16.0.2:27017")

	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(session.BuildInfo())
	fmt.Println(session.LiveServers())

	for i := 0; i < 100001; i++ {
		go test(session, i)
	}

	<-wait
	fmt.Println(session.LiveServers())
}

…of concurrent requests or a large amount of data is written at the same time
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant