github.com/cockroachdb/pebble@v1.1.1-0.20240513155919-3622ade60459/vfs/file_lock_unix.go (about) 1 // Copyright 2014 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris 6 // +build darwin dragonfly freebsd linux netbsd openbsd solaris 7 8 package vfs 9 10 import ( 11 "io" 12 "os" 13 "sync" 14 15 "github.com/cockroachdb/errors" 16 "golang.org/x/sys/unix" 17 ) 18 19 var lockedFiles struct { 20 mu struct { 21 sync.Mutex 22 files map[string]bool 23 } 24 } 25 26 // lockCloser hides all of an os.File's methods, except for Close. 27 type lockCloser struct { 28 name string 29 f *os.File 30 } 31 32 func (l lockCloser) Close() error { 33 lockedFiles.mu.Lock() 34 defer lockedFiles.mu.Unlock() 35 if !lockedFiles.mu.files[l.name] { 36 panic(errors.Errorf("lock file %q is not locked", l.name)) 37 } 38 delete(lockedFiles.mu.files, l.name) 39 40 return l.f.Close() 41 } 42 43 func (defaultFS) Lock(name string) (io.Closer, error) { 44 lockedFiles.mu.Lock() 45 defer lockedFiles.mu.Unlock() 46 if lockedFiles.mu.files == nil { 47 lockedFiles.mu.files = map[string]bool{} 48 } 49 if lockedFiles.mu.files[name] { 50 return nil, errors.New("lock held by current process") 51 } 52 53 f, err := os.Create(name) 54 if err != nil { 55 return nil, err 56 } 57 spec := unix.Flock_t{ 58 Type: unix.F_WRLCK, 59 Whence: io.SeekStart, 60 Start: 0, 61 Len: 0, // 0 means to lock the entire file. 62 Pid: int32(os.Getpid()), 63 } 64 if err := unix.FcntlFlock(f.Fd(), unix.F_SETLK, &spec); err != nil { 65 f.Close() 66 return nil, err 67 } 68 lockedFiles.mu.files[name] = true 69 return lockCloser{name, f}, nil 70 }