mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-16 11:08:39 +02:00
With -dlm, GetLk/SetLk/SetLkw and the flush/release cleanup paths go to the inode's owner filer via the PosixLock RPC instead of the local table, so flock/fcntl are honored across mounts. Advisory locking rides the same switch as whole-file write coordination — and is therefore off under writeback cache, which implies single-writer. Keys are the inode identity (HardLinkId else path); SetLkw is client-side polling with the FUSE cancel channel (no server wait queue); a per-mount session id namespaces owners; a local hint avoids a release RPC on every close. Background unlock/release RPCs are bounded so a stuck filer can't hang close().
95 lines
2.2 KiB
Go
95 lines
2.2 KiB
Go
package mount
|
|
|
|
import (
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/seaweedfs/go-fuse/v2/fuse"
|
|
"github.com/seaweedfs/seaweedfs/weed/filer/posixlock"
|
|
)
|
|
|
|
func TestPosixLockTypeMapping(t *testing.T) {
|
|
cases := []struct {
|
|
sys uint32
|
|
wire uint32
|
|
}{
|
|
{syscall.F_RDLCK, posixlock.Read},
|
|
{syscall.F_WRLCK, posixlock.Write},
|
|
{syscall.F_UNLCK, posixlock.Unlock},
|
|
}
|
|
for _, c := range cases {
|
|
if got := posixLockTypeToWire(c.sys); got != c.wire {
|
|
t.Errorf("toWire(%d) = %d, want %d", c.sys, got, c.wire)
|
|
}
|
|
if got := posixLockTypeFromWire(c.wire); got != c.sys {
|
|
t.Errorf("fromWire(%d) = %d, want %d", c.wire, got, c.sys)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPosixPollAcquireGrantedImmediately(t *testing.T) {
|
|
calls := 0
|
|
st := posixPollAcquire(nil, func() (bool, error) { calls++; return true, nil })
|
|
if st != fuse.OK || calls != 1 {
|
|
t.Fatalf("immediate grant: status=%v calls=%d", st, calls)
|
|
}
|
|
}
|
|
|
|
func TestPosixPollAcquireRetriesThenGrants(t *testing.T) {
|
|
calls := 0
|
|
st := posixPollAcquire(nil, func() (bool, error) {
|
|
calls++
|
|
return calls >= 3, nil
|
|
})
|
|
if st != fuse.OK || calls != 3 {
|
|
t.Fatalf("retry then grant: status=%v calls=%d", st, calls)
|
|
}
|
|
}
|
|
|
|
func TestPosixPollAcquireError(t *testing.T) {
|
|
if st := posixPollAcquire(nil, func() (bool, error) { return false, syscall.EIO }); st != fuse.EIO {
|
|
t.Fatalf("error should map to EIO, got %v", st)
|
|
}
|
|
}
|
|
|
|
func TestPosixPollAcquireCancel(t *testing.T) {
|
|
cancel := make(chan struct{})
|
|
close(cancel)
|
|
done := make(chan fuse.Status, 1)
|
|
go func() {
|
|
done <- posixPollAcquire(cancel, func() (bool, error) { return false, nil })
|
|
}()
|
|
select {
|
|
case st := <-done:
|
|
if st != fuse.EINTR {
|
|
t.Fatalf("cancel should map to EINTR, got %v", st)
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Fatal("poll did not return on cancel")
|
|
}
|
|
}
|
|
|
|
func TestPosixLockHint(t *testing.T) {
|
|
h := newPosixLockHint()
|
|
if h.has(1, 2) {
|
|
t.Fatal("empty hint should not report a lock")
|
|
}
|
|
h.add(1, 2)
|
|
h.add(1, 3)
|
|
if !h.has(1, 2) || !h.has(1, 3) {
|
|
t.Fatal("added owners should be reported")
|
|
}
|
|
h.drop(1, 2)
|
|
if h.has(1, 2) {
|
|
t.Fatal("dropped owner should be gone")
|
|
}
|
|
if !h.has(1, 3) {
|
|
t.Fatal("sibling owner should remain")
|
|
}
|
|
h.drop(1, 3)
|
|
if _, ok := h.m[1]; ok {
|
|
t.Fatal("inode entry should be removed when its last owner drops")
|
|
}
|
|
}
|