// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT package nfs4server import ( "sync" "time" "sourcedock.dev/petrbalvin/nfs/internal/nfs4" ) // A grace is the reclaim window of one handler: it opens when the handler // starts and closes after the configured period. The server recovers no // state across restarts, so a fresh window means every reclaim attempt // inside it is answered, and every attempt after it is NFS4ERR_NO_GRACE. type grace struct { mu sync.Mutex end time.Time done map[uint64]bool } func newGrace(period time.Duration) *grace { return &grace{end: time.Now().Add(period), done: make(map[uint64]bool)} } // active reports whether the reclaim window still runs. func (g *grace) active(now time.Time) bool { g.mu.Lock() defer g.mu.Unlock() return now.Before(g.end) } // reclaimOKFor reports whether the client may reclaim: inside the // window and without an earlier RECLAIM_COMPLETE. The status names the // refusal: NO_GRACE for a closed window, COMPLETE_ALREADY for a client // that announced it was done. func (g *grace) reclaimOKFor(clientid uint64, now time.Time) (bool, uint32) { g.mu.Lock() defer g.mu.Unlock() if !now.Before(g.end) { return false, nfs4.ErrNoGrace } if g.done[clientid] { return false, nfs4.ErrCompleteAlready } return true, 0 } // complete records the client's RECLAIM_COMPLETE and reports whether this // was the first announcement. func (g *grace) complete(clientid uint64, now time.Time) bool { g.mu.Lock() defer g.mu.Unlock() if g.done[clientid] { return false } g.done[clientid] = true return true }