file_lock_unix.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. //go:build !windows
  2. package core
  3. // Unix (Linux / macOS 等) 跨进程文件锁: 用 flock 对整个文件加排他锁。
  4. // 纯标准库 syscall。flock 锁关联打开的文件描述符, 不同进程 (或同进程不同
  5. // open 得到的 fd) 对同一文件加 LOCK_EX 互斥; 进程退出 / fd 关闭自动释放。
  6. import (
  7. "syscall"
  8. )
  9. // tryLock 非阻塞 (LOCK_NB) 地加排他锁 (LOCK_EX); 文件已被锁定时返回
  10. // ErrDatabaseLocked (flock 冲突 errno = EWOULDBLOCK)。
  11. func (ff *File) tryLock() error {
  12. if ff.fileLocked {
  13. return nil
  14. }
  15. err := syscall.Flock(int(ff.f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
  16. if err != nil {
  17. if err == syscall.EWOULDBLOCK {
  18. return ErrDatabaseLocked
  19. }
  20. return err
  21. }
  22. ff.fileLocked = true
  23. return nil
  24. }
  25. // tryRLock 非阻塞 (LOCK_NB) 地加共享锁 (LOCK_SH, 只读打开): 共享锁之间可共存,
  26. // 与排他锁 (LOCK_EX) 互斥; 冲突 errno EWOULDBLOCK → ErrDatabaseLocked。
  27. func (ff *File) tryRLock() error {
  28. if ff.fileLocked {
  29. return nil
  30. }
  31. err := syscall.Flock(int(ff.f.Fd()), syscall.LOCK_SH|syscall.LOCK_NB)
  32. if err != nil {
  33. if err == syscall.EWOULDBLOCK {
  34. return ErrDatabaseLocked
  35. }
  36. return err
  37. }
  38. ff.fileLocked = true
  39. return nil
  40. }
  41. // unlock 释放文件锁 (Close 路径调用; 错误忽略 —— 句柄关闭同样会释放)。
  42. func (ff *File) unlock() {
  43. if !ff.fileLocked {
  44. return
  45. }
  46. _ = syscall.Flock(int(ff.f.Fd()), syscall.LOCK_UN)
  47. ff.fileLocked = false
  48. }