Use freelist.Freelist for buffer.InMessage.

geesefs-0-30-9
Aaron Jacobs 2015-07-28 12:59:44 +10:00
parent 5b5d8ff8be
commit 3845b0f124
2 changed files with 46 additions and 37 deletions

View File

@ -27,6 +27,7 @@ import (
"golang.org/x/net/context"
"github.com/jacobsa/fuse/internal/buffer"
"github.com/jacobsa/fuse/internal/freelist"
"github.com/jacobsa/fuse/internal/fusekernel"
)
@ -71,18 +72,14 @@ type Connection struct {
mu sync.Mutex
// A freelist of InMessage structs, the allocation of which can be a hot spot
// for CPU usage. Each element is in an undefined state, and must be
// re-initialized.
//
// GUARDED_BY(mu)
messageFreelist []*buffer.InMessage
// A map from fuse "unique" request ID (*not* the op ID for logging used
// above) to a function that cancel's its associated context.
//
// GUARDED_BY(mu)
cancelFuncs map[uint64]func()
// Freelists, serviced by freelists.go.
inMessages freelist.Freelist // GUARDED_BY(mu)
}
// State that is maintained for each in-flight op. This is stuffed into the
@ -302,38 +299,11 @@ func (c *Connection) handleInterrupt(fuseID uint64) {
cancel()
}
// m.Init must be called.
func (c *Connection) allocateInMessage() (m *buffer.InMessage) {
c.mu.Lock()
defer c.mu.Unlock()
// Can we pull from the freelist?
l := len(c.messageFreelist)
if l != 0 {
m = c.messageFreelist[l-1]
c.messageFreelist = c.messageFreelist[:l-1]
return
}
// Otherwise, allocate a new one.
m = new(buffer.InMessage)
return
}
func (c *Connection) destroyInMessage(m *buffer.InMessage) {
c.mu.Lock()
defer c.mu.Unlock()
// Stick it on the freelist.
c.messageFreelist = append(c.messageFreelist, m)
}
// Read the next message from the kernel. The message must later be destroyed
// using destroyInMessage.
func (c *Connection) readMessage() (m *buffer.InMessage, err error) {
// Allocate a message.
m = c.allocateInMessage()
m = c.getInMessage()
// Loop past transient errors.
for {
@ -359,7 +329,7 @@ func (c *Connection) readMessage() (m *buffer.InMessage, err error) {
}
if err != nil {
c.destroyInMessage(m)
c.putInMessage(m)
m = nil
return
}
@ -459,7 +429,7 @@ func (c *Connection) Reply(ctx context.Context, opErr error) {
opID := state.opID
// Make sure we destroy the message when we're done.
defer c.destroyInMessage(m)
defer c.putInMessage(m)
// Clean up state for this op.
c.finishOp(m.Header().Opcode, m.Header().Unique)

39
freelists.go Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fuse
import (
"unsafe"
"github.com/jacobsa/fuse/internal/buffer"
)
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) getInMessage() (m *buffer.InMessage) {
c.mu.Lock()
m = (*buffer.InMessage)(c.inMessages.Get())
if m == nil {
m = new(buffer.InMessage)
}
c.mu.Unlock()
return
}
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) putInMessage(x *buffer.InMessage) {
c.mu.Lock()
c.inMessages.Put(unsafe.Pointer(x))
c.mu.Unlock()
}