RPC server in net/rpc package holds two free lists for Request
struct and Response
struct. Request
struct maintains this list via its next
field.
// Server represents an RPC Server.
type Server struct {
// ...
freeReq *Request // header node of Request free list
freeResp *Response // header node of Response free list
}
type Request struct {
ServiceMethod string // format: "Service.Method"
Seq uint64 // sequence number chosen by client
next *Request // for free list in Server
}
The free list in rpc server seems to be a object pool. When handling rpc request, server calls getRequest
to get a request instance from free list. After handling request, server calls freeRequest
to put request instance back to free list.
func (server *Server) getRequest() *Request {
server.reqLock.Lock()
req := server.freeReq
if req == nil {
req = new(Request) // free list is empty
} else {
server.freeReq = req.next // free list isn't empty
*req = Request{} // Why not reuse instance directly?
}
server.reqLock.Unlock()
return req
}
func (server *Server) freeRequest(req *Request) {
server.reqLock.Lock()
req.next = server.freeReq
server.freeReq = req
server.reqLock.Unlock()
}
I'm confused about the getRequest
function. When free list is empty, it creates a new instance as expected. When free list isn't empty, it executes *req = Request{}
. I think Request{}
also creates a new insance. So what's the point of holding this free list?
In addition, I wrote a demo to show the effect of the *req = Request{}
format statement.
type Student struct {
Name string
Age int
}
func main() {
s := &Student{"John", 20}
fmt.Printf("Address: %p Content: %v
", s, s)
*s = Student{"Frank", 18} // similar to *req = Request{}
fmt.Printf("Address: %p Content: %v
", s, s)
}
The output is:
Address: 0xc42000a4c0 Content: &{John 20}
Address: 0xc42000a4c0 Content: &{Frank 18}
So statement *req = Request{}
doesn't change the address of pointer, but it does change the content.