mirror of
https://github.com/miekg/dns.git
synced 2025-10-10 17:31:01 +02:00
Add a memory pool
Re-use memory for UDP queries.
This commit is contained in:
parent
7a27e05cb7
commit
49ece3e490
53
pool.go
Normal file
53
pool.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mkBuf(size int) []byte { return make([]byte, size) }
|
||||||
|
|
||||||
|
type queued struct {
|
||||||
|
when time.Time
|
||||||
|
buf []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func pool(size int) (get, give chan []byte) {
|
||||||
|
get = make(chan []byte)
|
||||||
|
give = make(chan []byte)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
q := new(list.List)
|
||||||
|
for {
|
||||||
|
e := q.Front()
|
||||||
|
if e == nil {
|
||||||
|
q.PushFront(queued{when: time.Now(), buf: mkBuf(size)})
|
||||||
|
e = q.Front()
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout := time.NewTimer(time.Minute)
|
||||||
|
select {
|
||||||
|
case b := <-give:
|
||||||
|
timeout.Stop()
|
||||||
|
q.PushFront(queued{when: time.Now(), buf: b})
|
||||||
|
|
||||||
|
case get <- e.Value.(queued).buf:
|
||||||
|
timeout.Stop()
|
||||||
|
q.Remove(e)
|
||||||
|
|
||||||
|
case <-timeout.C:
|
||||||
|
e := q.Front()
|
||||||
|
for e != nil {
|
||||||
|
n := e.Next()
|
||||||
|
if time.Since(e.Value.(queued).when) > time.Minute {
|
||||||
|
q.Remove(e)
|
||||||
|
e.Value = nil
|
||||||
|
}
|
||||||
|
e = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
31
server.go
31
server.go
@ -202,6 +202,8 @@ type Server struct {
|
|||||||
WriteTimeout time.Duration // the net.Conn.SetWriteTimeout value for new connections
|
WriteTimeout time.Duration // the net.Conn.SetWriteTimeout value for new connections
|
||||||
IdleTimeout func() time.Duration // TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966)
|
IdleTimeout func() time.Duration // TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966)
|
||||||
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>
|
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>
|
||||||
|
Pool bool // if true use a pool to recycle buffers for UDP queries
|
||||||
|
get, give chan []byte // channels for the pool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListenAndServe starts a nameserver on the configured address in *Server.
|
// ListenAndServe starts a nameserver on the configured address in *Server.
|
||||||
@ -210,6 +212,9 @@ func (srv *Server) ListenAndServe() error {
|
|||||||
if addr == "" {
|
if addr == "" {
|
||||||
addr = ":domain"
|
addr = ":domain"
|
||||||
}
|
}
|
||||||
|
if srv.Pool {
|
||||||
|
srv.get, srv.give = pool(srv.UDPSize)
|
||||||
|
}
|
||||||
switch srv.Net {
|
switch srv.Net {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
a, e := net.ResolveTCPAddr(srv.Net, addr)
|
a, e := net.ResolveTCPAddr(srv.Net, addr)
|
||||||
@ -279,6 +284,7 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
|||||||
for {
|
for {
|
||||||
m, a, e := srv.readUDP(l, rtimeout)
|
m, a, e := srv.readUDP(l, rtimeout)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
|
println(e.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
go srv.serve(a, handler, m, l, nil)
|
go srv.serve(a, handler, m, l, nil)
|
||||||
@ -292,7 +298,12 @@ func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, t *net
|
|||||||
q := 0
|
q := 0
|
||||||
Redo:
|
Redo:
|
||||||
req := new(Msg)
|
req := new(Msg)
|
||||||
if req.Unpack(m) != nil { // Send a FormatError back
|
err := req.Unpack(m)
|
||||||
|
println("GONNT")
|
||||||
|
if srv.Pool && u != nil {
|
||||||
|
srv.give <- m[:srv.UDPSize]
|
||||||
|
}
|
||||||
|
if err != nil { // Send a FormatError back
|
||||||
x := new(Msg)
|
x := new(Msg)
|
||||||
x.SetRcodeFormatError(req)
|
x.SetRcodeFormatError(req)
|
||||||
w.WriteMsg(x)
|
w.WriteMsg(x)
|
||||||
@ -347,11 +358,11 @@ func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, ErrConn
|
return nil, ErrShortRead
|
||||||
}
|
}
|
||||||
length, _ := unpackUint16(l, 0)
|
length, _ := unpackUint16(l, 0)
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
return nil, ErrConn
|
return nil, ErrShortRead
|
||||||
}
|
}
|
||||||
m := make([]byte, int(length))
|
m := make([]byte, int(length))
|
||||||
n, err = conn.Read(m[:int(length)])
|
n, err = conn.Read(m[:int(length)])
|
||||||
@ -359,7 +370,7 @@ func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, ErrConn
|
return nil, ErrShortRead
|
||||||
}
|
}
|
||||||
i := n
|
i := n
|
||||||
for i < int(length) {
|
for i < int(length) {
|
||||||
@ -376,10 +387,18 @@ func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, er
|
|||||||
|
|
||||||
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, net.Addr, error) {
|
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, net.Addr, error) {
|
||||||
conn.SetReadDeadline(time.Now().Add(timeout))
|
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
m := make([]byte, srv.UDPSize)
|
var m []byte
|
||||||
|
if srv.Pool {
|
||||||
|
m = <-srv.get
|
||||||
|
} else {
|
||||||
|
m = make([]byte, srv.UDPSize)
|
||||||
|
}
|
||||||
n, a, e := conn.ReadFromUDP(m)
|
n, a, e := conn.ReadFromUDP(m)
|
||||||
if e != nil || n == 0 {
|
if e != nil || n == 0 {
|
||||||
return nil, nil, ErrConn
|
if e != nil {
|
||||||
|
return nil, nil, e
|
||||||
|
}
|
||||||
|
return nil, nil, ErrShortRead
|
||||||
}
|
}
|
||||||
m = m[:n]
|
m = m[:n]
|
||||||
return m, a, nil
|
return m, a, nil
|
||||||
|
Loading…
x
Reference in New Issue
Block a user