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