mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-18 20:18:27 +02:00
* filer: POSIX advisory lock set primitive (phase 1) Pure per-inode conflict/coalesce/range-split logic for fcntl byte-range and flock whole-file locks, extracted from the mount's PosixLockTable without its wait queue or inode-map concurrency. Owner identity is (Sid, Owner) so the same FUSE owner on different mounts never aliases, and ReleaseSession reaps a dead mount's locks. The owner filer will hold one Set per inode under the per-path lock; no concurrency control here. * test: tolerate transient FUSE invisibility in ConcurrentReadWrite A concurrent truncating overwrite leaves a short-lived dentry/cache window where the file is momentarily ENOENT to another opener. Retry the reads and writes a few times before failing, as ConcurrentDirectoryOperations does. * filer: serialize the POSIX lock set for entry metadata Versioned fixed-width binary encoding of a Set, so an inode's held locks can ride in its entry metadata: a lock op materializes the Set from the blob, applies under the per-path lock, and writes it back. Empty set encodes to nil so a lock-free inode carries no blob. * filer: encode the POSIX lock set as protobuf Replace the hand-rolled fixed-width codec with a LockSetProto message, so the metadata blob can gain fields without a format-version migration. proto.Unmarshal already rejects a malformed blob, so the explicit version and length checks go away. Marshal now returns an error to match.
59 lines
1.5 KiB
Go
59 lines
1.5 KiB
Go
package posixlock
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
// The held lock set rides in an inode's entry metadata, so the wire format must
|
|
// stay backward compatible across filer versions. It is a protobuf message
|
|
// (LockSetProto), so new fields can be added without breaking old readers.
|
|
|
|
// Marshal encodes the held locks for storage in the inode's entry metadata. A
|
|
// lock-free set encodes to nil, so an inode that holds no locks carries no blob.
|
|
func (s *Set) Marshal() ([]byte, error) {
|
|
if len(s.locks) == 0 {
|
|
return nil, nil
|
|
}
|
|
pb := &LockSetProto{Locks: make([]*LockProto, len(s.locks))}
|
|
for i, l := range s.locks {
|
|
pb.Locks[i] = &LockProto{
|
|
Start: l.Start,
|
|
End: l.End,
|
|
Type: l.Type,
|
|
Sid: l.Sid,
|
|
Owner: l.Owner,
|
|
Pid: l.Pid,
|
|
IsFlock: l.IsFlock,
|
|
}
|
|
}
|
|
return proto.Marshal(pb)
|
|
}
|
|
|
|
// Unmarshal decodes a Set produced by Marshal. Empty input is an empty set, so a
|
|
// missing metadata key reads back as "no locks held". A malformed blob is
|
|
// rejected rather than silently misread.
|
|
func Unmarshal(b []byte) (*Set, error) {
|
|
if len(b) == 0 {
|
|
return &Set{}, nil
|
|
}
|
|
pb := &LockSetProto{}
|
|
if err := proto.Unmarshal(b, pb); err != nil {
|
|
return nil, fmt.Errorf("posixlock: %w", err)
|
|
}
|
|
locks := make([]Range, len(pb.Locks))
|
|
for i, l := range pb.Locks {
|
|
locks[i] = Range{
|
|
Start: l.Start,
|
|
End: l.End,
|
|
Type: l.Type,
|
|
Sid: l.Sid,
|
|
Owner: l.Owner,
|
|
Pid: l.Pid,
|
|
IsFlock: l.IsFlock,
|
|
}
|
|
}
|
|
return &Set{locks: locks}, nil
|
|
}
|