...

Source file src/go.etcd.io/bbolt/bolt_unix.go

Documentation: go.etcd.io/bbolt

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

View as plain text