blob: babad657862bbffea24725d320e586e9186384cb [file] [log] [blame]
khenaidoo59ce9dd2019-11-11 13:05:32 -05001package bbolt
2
3import (
4 "fmt"
5 "syscall"
6 "time"
7 "unsafe"
8
9 "golang.org/x/sys/unix"
10)
11
12// flock acquires an advisory lock on a file descriptor.
13func flock(db *DB, exclusive bool, timeout time.Duration) error {
14 var t time.Time
15 if timeout != 0 {
16 t = time.Now()
17 }
18 fd := db.file.Fd()
19 var lockType int16
20 if exclusive {
21 lockType = syscall.F_WRLCK
22 } else {
23 lockType = syscall.F_RDLCK
24 }
25 for {
26 // Attempt to obtain an exclusive lock.
27 lock := syscall.Flock_t{Type: lockType}
28 err := syscall.FcntlFlock(fd, syscall.F_SETLK, &lock)
29 if err == nil {
30 return nil
31 } else if err != syscall.EAGAIN {
32 return err
33 }
34
35 // If we timed out then return an error.
36 if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
37 return ErrTimeout
38 }
39
40 // Wait for a bit and try again.
41 time.Sleep(flockRetryTimeout)
42 }
43}
44
45// funlock releases an advisory lock on a file descriptor.
46func funlock(db *DB) error {
47 var lock syscall.Flock_t
48 lock.Start = 0
49 lock.Len = 0
50 lock.Type = syscall.F_UNLCK
51 lock.Whence = 0
52 return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock)
53}
54
55// mmap memory maps a DB's data file.
56func mmap(db *DB, sz int) error {
57 // Map the data file to memory.
58 b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
59 if err != nil {
60 return err
61 }
62
63 // Advise the kernel that the mmap is accessed randomly.
64 if err := unix.Madvise(b, syscall.MADV_RANDOM); err != nil {
65 return fmt.Errorf("madvise: %s", err)
66 }
67
68 // Save the original byte slice and convert to a byte array pointer.
69 db.dataref = b
70 db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
71 db.datasz = sz
72 return nil
73}
74
75// munmap unmaps a DB's data file from memory.
76func munmap(db *DB) error {
77 // Ignore the unmap if we have no mapped data.
78 if db.dataref == nil {
79 return nil
80 }
81
82 // Unmap using the original byte slice.
83 err := unix.Munmap(db.dataref)
84 db.dataref = nil
85 db.data = nil
86 db.datasz = 0
87 return err
88}