Browse Source

avoid goroutine leak

v2ray 9 năm trước cách đây
mục cha
commit
09ea65687c
1 tập tin đã thay đổi với 24 bổ sung20 xóa
  1. 24 20
      app/dns/nameserver.go

+ 24 - 20
app/dns/nameserver.go

@@ -16,7 +16,9 @@ import (
 )
 
 const (
-	DefaultTTL = uint32(3600)
+	DefaultTTL       = uint32(3600)
+	CleanupInterval  = time.Second * 120
+	CleanupThreshold = 512
 )
 
 type ARecord struct {
@@ -35,9 +37,10 @@ type PendingRequest struct {
 
 type UDPNameServer struct {
 	sync.Mutex
-	address   v2net.Destination
-	requests  map[uint16]*PendingRequest
-	udpServer *hub.UDPServer
+	address     v2net.Destination
+	requests    map[uint16]*PendingRequest
+	udpServer   *hub.UDPServer
+	nextCleanup time.Time
 }
 
 func NewUDPNameServer(address v2net.Destination, dispatcher dispatcher.PacketDispatcher) *UDPNameServer {
@@ -46,35 +49,36 @@ func NewUDPNameServer(address v2net.Destination, dispatcher dispatcher.PacketDis
 		requests:  make(map[uint16]*PendingRequest),
 		udpServer: hub.NewUDPServer(dispatcher),
 	}
-	go s.Cleanup()
 	return s
 }
 
 // @Private
 func (this *UDPNameServer) Cleanup() {
-	for {
-		time.Sleep(time.Second * 60)
-		expiredRequests := make([]uint16, 0, 16)
-		now := time.Now()
-		this.Lock()
-		for id, r := range this.requests {
-			if r.expire.Before(now) {
-				expiredRequests = append(expiredRequests, id)
-				close(r.response)
-			}
-		}
-		for _, id := range expiredRequests {
-			delete(this.requests, id)
+	expiredRequests := make([]uint16, 0, 16)
+	now := time.Now()
+	this.Lock()
+	for id, r := range this.requests {
+		if r.expire.Before(now) {
+			expiredRequests = append(expiredRequests, id)
+			close(r.response)
 		}
-		this.Unlock()
-		expiredRequests = nil
 	}
+	for _, id := range expiredRequests {
+		delete(this.requests, id)
+	}
+	this.Unlock()
+	expiredRequests = nil
 }
 
 // @Private
 func (this *UDPNameServer) AssignUnusedID(response chan<- *ARecord) uint16 {
 	var id uint16
 	this.Lock()
+	if len(this.requests) > CleanupThreshold && this.nextCleanup.Before(time.Now()) {
+		this.nextCleanup = time.Now().Add(CleanupInterval)
+		go this.Cleanup()
+	}
+
 	for {
 		id = uint16(rand.Intn(65536))
 		if _, found := this.requests[id]; found {