blob: 5f2bb5145199018ce6fcac8c59b01e552c30bdaf [file] [log] [blame]
khenaidoo59ce9dd2019-11-11 13:05:32 -05001// +build !windows,!plan9,!solaris
2
3package bbolt
4
5import (
6 "fmt"
7 "syscall"
8 "time"
9 "unsafe"
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 flag := syscall.LOCK_NB
20 if exclusive {
21 flag |= syscall.LOCK_EX
22 } else {
23 flag |= syscall.LOCK_SH
24 }
25 for {
26 // Attempt to obtain an exclusive lock.
27 err := syscall.Flock(int(fd), flag)
28 if err == nil {
29 return nil
30 } else if err != syscall.EWOULDBLOCK {
31 return err
32 }
33
34 // If we timed out then return an error.
35 if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
36 return ErrTimeout
37 }
38
39 // Wait for a bit and try again.
40 time.Sleep(flockRetryTimeout)
41 }
42}
43
44// funlock releases an advisory lock on a file descriptor.
45func funlock(db *DB) error {
46 return syscall.Flock(int(db.file.Fd()), syscall.LOCK_UN)
47}
48
49// mmap memory maps a DB's data file.
50func mmap(db *DB, sz int) error {
51 // Map the data file to memory.
52 b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
53 if err != nil {
54 return err
55 }
56
57 // Advise the kernel that the mmap is accessed randomly.
58 err = madvise(b, syscall.MADV_RANDOM)
59 if err != nil && err != syscall.ENOSYS {
60 // Ignore not implemented error in kernel because it still works.
61 return fmt.Errorf("madvise: %s", err)
62 }
63
64 // Save the original byte slice and convert to a byte array pointer.
65 db.dataref = b
66 db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
67 db.datasz = sz
68 return nil
69}
70
71// munmap unmaps a DB's data file from memory.
72func munmap(db *DB) error {
73 // Ignore the unmap if we have no mapped data.
74 if db.dataref == nil {
75 return nil
76 }
77
78 // Unmap using the original byte slice.
79 err := syscall.Munmap(db.dataref)
80 db.dataref = nil
81 db.data = nil
82 db.datasz = 0
83 return err
84}
85
86// NOTE: This function is copied from stdlib because it is not available on darwin.
87func madvise(b []byte, advice int) (err error) {
88 _, _, e1 := syscall.Syscall(syscall.SYS_MADVISE, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), uintptr(advice))
89 if e1 != 0 {
90 err = e1
91 }
92 return
93}