package llmfs
import (
"sync"
"github.com/NERVsystems/llm9p/internal/llm"
"github.com/NERVsystems/llm9p/internal/protocol"
)
// sessionRefFile wraps a protocol.File and tracks a reference to its session.
// It calls sm.IncRef(id) on Open and sm.DecRef(id) on the first Close, so
// that sessions are automatically cleaned up when all their files are clunked.
type sessionRefFile struct {
protocol.File
sm *llm.SessionManager
id int
once sync.Once
opened bool
}
func (r *sessionRefFile) Open(mode uint8) error {
err := r.File.Open(mode)
if err == nil {
r.opened = true
r.sm.IncRef(r.id)
}
return err
}
func (r *sessionRefFile) Close() error {
err := r.File.Close()
if r.opened {
r.once.Do(func() {
r.sm.DecRef(r.id)
})
}
return err
}
// sessionRefDir wraps a protocol.Dir (SessionDir) with the same ref counting.
// It additionally overrides Lookup so that child files are also ref-counted.
type sessionRefDir struct {
protocol.Dir
sm *llm.SessionManager
id int
once sync.Once
opened bool
}
func (r *sessionRefDir) Open(mode uint8) error {
err := r.Dir.Open(mode)
if err == nil {
r.opened = true
r.sm.IncRef(r.id)
}
return err
}
func (r *sessionRefDir) Close() error {
err := r.Dir.Close()
if r.opened {
r.once.Do(func() {
r.sm.DecRef(r.id)
})
}
return err
}
// Lookup wraps child files in sessionRefFile so each open fid contributes
// its own reference to the session.
func (r *sessionRefDir) Lookup(name string) (protocol.File, error) {
f, err := r.Dir.Lookup(name)
if err != nil {
return nil, err
}
return &sessionRefFile{File: f, sm: r.sm, id: r.id}, nil
}