12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- // +build !windows,!plan9,!solaris
- package bolt
- import (
- "fmt"
- "os"
- "syscall"
- "time"
- "unsafe"
- )
- // flock acquires an advisory lock on a file descriptor.
- func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
- var t time.Time
- if timeout != 0 {
- t = time.Now()
- }
- fd := db.file.Fd()
- flag := syscall.LOCK_NB
- if exclusive {
- flag |= syscall.LOCK_EX
- } else {
- flag |= syscall.LOCK_SH
- }
- for {
- // Attempt to obtain an exclusive lock.
- err := syscall.Flock(int(fd), flag)
- if err == nil {
- return nil
- } else if err != syscall.EWOULDBLOCK {
- return err
- }
- // If we timed out then return an error.
- if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
- return ErrTimeout
- }
- // Wait for a bit and try again.
- time.Sleep(flockRetryTimeout)
- }
- }
- // funlock releases an advisory lock on a file descriptor.
- func funlock(db *DB) error {
- return syscall.Flock(int(db.file.Fd()), syscall.LOCK_UN)
- }
- // mmap memory maps a DB's data file.
- func mmap(db *DB, sz int) error {
- // Map the data file to memory.
- b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
- if err != nil {
- return err
- }
- // Advise the kernel that the mmap is accessed randomly.
- err = madvise(b, syscall.MADV_RANDOM)
- if err != nil && err != syscall.ENOSYS {
- // Ignore not implemented error in kernel because it still works.
- return fmt.Errorf("madvise: %s", err)
- }
- // Save the original byte slice and convert to a byte array pointer.
- db.dataref = b
- db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
- db.datasz = sz
- return nil
- }
- // munmap unmaps a DB's data file from memory.
- func munmap(db *DB) error {
- // Ignore the unmap if we have no mapped data.
- if db.dataref == nil {
- return nil
- }
- // Unmap using the original byte slice.
- err := syscall.Munmap(db.dataref)
- db.dataref = nil
- db.data = nil
- db.datasz = 0
- return err
- }
- // NOTE: This function is copied from stdlib because it is not available on darwin.
- func madvise(b []byte, advice int) (err error) {
- _, _, e1 := syscall.Syscall(syscall.SYS_MADVISE, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), uintptr(advice))
- if e1 != 0 {
- err = e1
- }
- return
- }
|