Commit 0d66ca07 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

After copying the input buffer, reuse it.

parent bb1bc0b5
......@@ -145,25 +145,11 @@ func (me *MountState) BufferPoolStats() string {
func (me *MountState) newRequest() *request {
r := &request{
status: OK,
pool: me.buffers,
bufferPoolInputBuf: me.buffers.AllocBuffer(uint32(me.opts.MaxWrite + 4096)),
}
r.inputBuf = r.bufferPoolInputBuf
return r
}
func (me *MountState) readRequest(req *request) Status {
n, err := me.mountFile.Read(req.inputBuf)
// If we start timing before the read, we may take into
// account waiting for input into the timing.
if me.latencies != nil {
req.startNs = time.Now().UnixNano()
}
req.inputBuf = req.inputBuf[0:n]
return ToStatus(err)
}
func (me *MountState) recordStats(req *request) {
if me.latencies != nil {
endNs := time.Now().UnixNano()
......@@ -189,10 +175,16 @@ func (me *MountState) Loop() {
}
func (me *MountState) loop() {
var dest []byte
for {
req := me.newRequest()
errNo := me.readRequest(req)
if !errNo.Ok() {
if dest == nil {
dest = me.buffers.AllocBuffer(uint32(me.opts.MaxWrite + 4096))
}
n, err := me.mountFile.Read(dest)
if err != nil {
errNo := ToStatus(err)
// Retry.
if errNo == ENOENT {
continue
......@@ -206,6 +198,14 @@ func (me *MountState) loop() {
log.Printf("Failed to read from fuse conn: %v", errNo)
break
}
req := me.newRequest()
if me.latencies != nil {
req.startNs = time.Now().UnixNano()
}
if req.setInput(dest[:n]) {
dest = nil
}
// When closely analyzing timings, the context switch
// generates some delay. While unfortunate, the
......
......@@ -15,18 +15,16 @@ func (req *request) Discard() {
req.pool.FreeBuffer(req.bufferPoolInputBuf)
}
// The largest input without data is 128 (setattr). This also fits small
// requests with short filenames.
const SMALL_BUF_THRESHOLD = 128
type request struct {
// the input, if obtained through bufferpool
bufferPoolInputBuf []byte
pool BufferPool
// If we have a small input, we quickly copy it to here,
// and give back the large buffer to buffer pool.
smallInputBuf [SMALL_BUF_THRESHOLD]byte
// If we have a small input, we quickly copy it to here, and
// give back the large buffer to buffer pool. The largest
// input without data is 128 (setattr). 128 also fits small
// requests with short filenames.
smallInputBuf [128]byte
inputBuf []byte
......@@ -103,6 +101,18 @@ func (me *request) OutputDebug() string {
operationName(me.inHeader.Opcode), me.status, dataStr, flatStr)
}
// setInput returns true if it takes ownership of the argument, false if not.
func (me *request) setInput(input []byte) bool {
if len(input) < len(me.smallInputBuf) {
copy(me.smallInputBuf[:], input)
me.inputBuf = me.smallInputBuf[:len(input)]
return false
}
me.inputBuf = input
me.bufferPoolInputBuf = input
return true
}
func (me *request) parse() {
inHSize := int(unsafe.Sizeof(raw.InHeader{}))
......@@ -111,16 +121,6 @@ func (me *request) parse() {
return
}
// We return the input buffer early if possible. Only write
// requests require a large input buffer, so if we hang onto
// the large buffer, we create unnecessary memory pressure.
if len(me.inputBuf) < SMALL_BUF_THRESHOLD {
copy(me.smallInputBuf[:], me.inputBuf)
me.inputBuf = me.smallInputBuf[:len(me.inputBuf)]
me.pool.FreeBuffer(me.bufferPoolInputBuf)
me.bufferPoolInputBuf = nil
}
me.inHeader = (*raw.InHeader)(unsafe.Pointer(&me.inputBuf[0]))
me.arg = me.inputBuf[inHSize:]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment