bolt_unix.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. //go:build !windows && !plan9 && !solaris && !aix
  2. // +build !windows,!plan9,!solaris,!aix
  3. package bbolt
  4. import (
  5. "fmt"
  6. "syscall"
  7. "time"
  8. "unsafe"
  9. "golang.org/x/sys/unix"
  10. )
  11. // flock acquires an advisory lock on a file descriptor.
  12. func flock(db *DB, exclusive bool, timeout time.Duration) error {
  13. var t time.Time
  14. if timeout != 0 {
  15. t = time.Now()
  16. }
  17. fd := db.file.Fd()
  18. flag := syscall.LOCK_NB
  19. if exclusive {
  20. flag |= syscall.LOCK_EX
  21. } else {
  22. flag |= syscall.LOCK_SH
  23. }
  24. for {
  25. // Attempt to obtain an exclusive lock.
  26. err := syscall.Flock(int(fd), flag)
  27. if err == nil {
  28. return nil
  29. } else if err != syscall.EWOULDBLOCK {
  30. return err
  31. }
  32. // If we timed out then return an error.
  33. if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
  34. return ErrTimeout
  35. }
  36. // Wait for a bit and try again.
  37. time.Sleep(flockRetryTimeout)
  38. }
  39. }
  40. // funlock releases an advisory lock on a file descriptor.
  41. func funlock(db *DB) error {
  42. return syscall.Flock(int(db.file.Fd()), syscall.LOCK_UN)
  43. }
  44. // mmap memory maps a DB's data file.
  45. func mmap(db *DB, sz int) error {
  46. // Map the data file to memory.
  47. b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
  48. if err != nil {
  49. return err
  50. }
  51. // Advise the kernel that the mmap is accessed randomly.
  52. err = unix.Madvise(b, syscall.MADV_RANDOM)
  53. if err != nil && err != syscall.ENOSYS {
  54. // Ignore not implemented error in kernel because it still works.
  55. return fmt.Errorf("madvise: %s", err)
  56. }
  57. // Save the original byte slice and convert to a byte array pointer.
  58. db.dataref = b
  59. db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
  60. db.datasz = sz
  61. return nil
  62. }
  63. // munmap unmaps a DB's data file from memory.
  64. func munmap(db *DB) error {
  65. // Ignore the unmap if we have no mapped data.
  66. if db.dataref == nil {
  67. return nil
  68. }
  69. // Unmap using the original byte slice.
  70. err := unix.Munmap(db.dataref)
  71. db.dataref = nil
  72. db.data = nil
  73. db.datasz = 0
  74. return err
  75. }