Refactored the way freelists work.
commit
2d3078f8b9
|
@ -27,6 +27,7 @@ import (
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/jacobsa/fuse/internal/buffer"
|
"github.com/jacobsa/fuse/internal/buffer"
|
||||||
|
"github.com/jacobsa/fuse/internal/freelist"
|
||||||
"github.com/jacobsa/fuse/internal/fusekernel"
|
"github.com/jacobsa/fuse/internal/fusekernel"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -71,18 +72,14 @@ type Connection struct {
|
||||||
|
|
||||||
mu sync.Mutex
|
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
|
// A map from fuse "unique" request ID (*not* the op ID for logging used
|
||||||
// above) to a function that cancel's its associated context.
|
// above) to a function that cancel's its associated context.
|
||||||
//
|
//
|
||||||
// GUARDED_BY(mu)
|
// GUARDED_BY(mu)
|
||||||
cancelFuncs map[uint64]func()
|
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
|
// 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()
|
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
|
// Read the next message from the kernel. The message must later be destroyed
|
||||||
// using destroyInMessage.
|
// using destroyInMessage.
|
||||||
func (c *Connection) readMessage() (m *buffer.InMessage, err error) {
|
func (c *Connection) readMessage() (m *buffer.InMessage, err error) {
|
||||||
// Allocate a message.
|
// Allocate a message.
|
||||||
m = c.allocateInMessage()
|
m = c.getInMessage()
|
||||||
|
|
||||||
// Loop past transient errors.
|
// Loop past transient errors.
|
||||||
for {
|
for {
|
||||||
|
@ -359,7 +329,7 @@ func (c *Connection) readMessage() (m *buffer.InMessage, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.destroyInMessage(m)
|
c.putInMessage(m)
|
||||||
m = nil
|
m = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -459,7 +429,7 @@ func (c *Connection) Reply(ctx context.Context, opErr error) {
|
||||||
opID := state.opID
|
opID := state.opID
|
||||||
|
|
||||||
// Make sure we destroy the message when we're done.
|
// Make sure we destroy the message when we're done.
|
||||||
defer c.destroyInMessage(m)
|
defer c.putInMessage(m)
|
||||||
|
|
||||||
// Clean up state for this op.
|
// Clean up state for this op.
|
||||||
c.finishOp(m.Header().Opcode, m.Header().Unique)
|
c.finishOp(m.Header().Opcode, m.Header().Unique)
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
// 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 freelist
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// A freelist for arbitrary pointers. Not safe for concurrent access.
|
||||||
|
type Freelist struct {
|
||||||
|
list []unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an element from the freelist, returning nil if empty.
|
||||||
|
func (fl *Freelist) Get() (p unsafe.Pointer) {
|
||||||
|
l := len(fl.list)
|
||||||
|
if l == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p = fl.list[l-1]
|
||||||
|
fl.list = fl.list[:l-1]
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contribute an element back to the freelist.
|
||||||
|
func (fl *Freelist) Put(p unsafe.Pointer) {
|
||||||
|
fl.list = append(fl.list, p)
|
||||||
|
}
|
Loading…
Reference in New Issue