github.com/bhojpur/cache@v0.0.4/pkg/memory/storage_unix_solaris.go (about)

     1  package memory
     2  
     3  // Copyright (c) 2018 Bhojpur Consulting Private Limited, India. All rights reserved.
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in
    13  // all copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    21  // THE SOFTWARE.
    22  
    23  import (
    24  	"fmt"
    25  	"syscall"
    26  	"time"
    27  	"unsafe"
    28  
    29  	"golang.org/x/sys/unix"
    30  )
    31  
    32  // flock acquires an advisory lock on a file descriptor.
    33  func flock(db *DB, exclusive bool, timeout time.Duration) error {
    34  	var t time.Time
    35  	if timeout != 0 {
    36  		t = time.Now()
    37  	}
    38  	fd := db.file.Fd()
    39  	var lockType int16
    40  	if exclusive {
    41  		lockType = syscall.F_WRLCK
    42  	} else {
    43  		lockType = syscall.F_RDLCK
    44  	}
    45  	for {
    46  		// Attempt to obtain an exclusive lock.
    47  		lock := syscall.Flock_t{Type: lockType}
    48  		err := syscall.FcntlFlock(fd, syscall.F_SETLK, &lock)
    49  		if err == nil {
    50  			return nil
    51  		} else if err != syscall.EAGAIN {
    52  			return err
    53  		}
    54  
    55  		// If we timed out then return an error.
    56  		if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
    57  			return ErrTimeout
    58  		}
    59  
    60  		// Wait for a bit and try again.
    61  		time.Sleep(flockRetryTimeout)
    62  	}
    63  }
    64  
    65  // funlock releases an advisory lock on a file descriptor.
    66  func funlock(db *DB) error {
    67  	var lock syscall.Flock_t
    68  	lock.Start = 0
    69  	lock.Len = 0
    70  	lock.Type = syscall.F_UNLCK
    71  	lock.Whence = 0
    72  	return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock)
    73  }
    74  
    75  // mmap memory maps a DB's data file.
    76  func mmap(db *DB, sz int) error {
    77  	// Map the data file to memory.
    78  	b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
    79  	if err != nil {
    80  		return err
    81  	}
    82  
    83  	// Advise the kernel that the mmap is accessed randomly.
    84  	if err := unix.Madvise(b, syscall.MADV_RANDOM); err != nil {
    85  		return fmt.Errorf("madvise: %s", err)
    86  	}
    87  
    88  	// Save the original byte slice and convert to a byte array pointer.
    89  	db.dataref = b
    90  	db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
    91  	db.datasz = sz
    92  	return nil
    93  }
    94  
    95  // munmap unmaps a DB's data file from memory.
    96  func munmap(db *DB) error {
    97  	// Ignore the unmap if we have no mapped data.
    98  	if db.dataref == nil {
    99  		return nil
   100  	}
   101  
   102  	// Unmap using the original byte slice.
   103  	err := unix.Munmap(db.dataref)
   104  	db.dataref = nil
   105  	db.data = nil
   106  	db.datasz = 0
   107  	return err
   108  }