server: fix BlockingReadMode truncation, separate stream/blocking paths
BlockingReadMode had the same 512-byte truncation bug: it returned EOF on offset>0 before the full content was delivered. Now caches content on the fid like normal reads. StreamMode is separated into its own path since it has fundamentally different semantics (each Tread blocks for the next chunk, no caching).
This commit is contained in:
parent
cfc526b0d7
commit
7dfd769c25
|
|
@ -468,11 +468,15 @@ func read(root *fs.Tree, cs *connState, fc *plan9.Fcall, ctx context.Context) *p
|
|||
return errFcall(fc, "file not opened")
|
||||
}
|
||||
|
||||
if entry.BlockingReadMode() && fc.Offset > 0 {
|
||||
return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Count: 0}
|
||||
}
|
||||
|
||||
if entry.BlockingReadMode() || entry.StreamMode() {
|
||||
if entry.BlockingReadMode() {
|
||||
// Serve from cache if we already have content (multi-Tread paging).
|
||||
if f.readCache != nil {
|
||||
if int(fc.Offset) >= len(f.readCache) {
|
||||
return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Count: 0}
|
||||
}
|
||||
return readSlice(fc, f.readCache)
|
||||
}
|
||||
// First Tread: block for content.
|
||||
cs.mu.RLock()
|
||||
f, fidOK := cs.fids[fc.Fid]
|
||||
var base string
|
||||
|
|
@ -480,13 +484,7 @@ func read(root *fs.Tree, cs *connState, fc *plan9.Fcall, ctx context.Context) *p
|
|||
base = f.waitBase
|
||||
}
|
||||
cs.mu.RUnlock()
|
||||
var waitCtx context.Context
|
||||
var waitCancel context.CancelFunc
|
||||
if entry.StreamMode() {
|
||||
waitCtx, waitCancel = context.WithCancel(ctx)
|
||||
} else {
|
||||
waitCtx, waitCancel = context.WithTimeout(ctx, 5*time.Second)
|
||||
}
|
||||
waitCtx, waitCancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer waitCancel()
|
||||
content, nextBase, err := entry.BlockingRead(waitCtx, base)
|
||||
if err != nil {
|
||||
|
|
@ -499,16 +497,38 @@ func read(root *fs.Tree, cs *connState, fc *plan9.Fcall, ctx context.Context) *p
|
|||
}
|
||||
cs.mu.Unlock()
|
||||
}
|
||||
if entry.StreamMode() {
|
||||
count := int(fc.Count)
|
||||
if count > len(content) {
|
||||
count = len(content)
|
||||
}
|
||||
return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Count: uint32(count), Data: content[:count]}
|
||||
}
|
||||
f.readCache = content
|
||||
return readSlice(fc, content)
|
||||
}
|
||||
|
||||
if entry.StreamMode() {
|
||||
cs.mu.RLock()
|
||||
f, fidOK := cs.fids[fc.Fid]
|
||||
var base string
|
||||
if fidOK {
|
||||
base = f.waitBase
|
||||
}
|
||||
cs.mu.RUnlock()
|
||||
waitCtx, waitCancel := context.WithCancel(ctx)
|
||||
defer waitCancel()
|
||||
content, nextBase, err := entry.BlockingRead(waitCtx, base)
|
||||
if err != nil {
|
||||
return errFcall(fc, err.Error())
|
||||
}
|
||||
if nextBase != "" {
|
||||
cs.mu.Lock()
|
||||
if f, ok := cs.fids[fc.Fid]; ok {
|
||||
f.waitBase = nextBase
|
||||
}
|
||||
cs.mu.Unlock()
|
||||
}
|
||||
count := int(fc.Count)
|
||||
if count > len(content) {
|
||||
count = len(content)
|
||||
}
|
||||
return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Count: uint32(count), Data: content[:count]}
|
||||
}
|
||||
|
||||
// Normal file read: cache content on first Tread, serve via readSlice.
|
||||
// This handles the case where io.ReadAll issues multiple Treads at
|
||||
// increasing offsets (buffer starts at 512 bytes and grows).
|
||||
|
|
|
|||
Loading…
Reference in New Issue