github.com/bhojpur/cache@v0.0.4/pkg/memory/storage_windows.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  	"os"
    26  	"syscall"
    27  	"time"
    28  	"unsafe"
    29  
    30  	"golang.org/x/sys/windows"
    31  )
    32  
    33  // fdatasync flushes written data to a file descriptor.
    34  func fdatasync(db *DB) error {
    35  	return db.file.Sync()
    36  }
    37  
    38  // flock acquires an advisory lock on a file descriptor.
    39  func flock(db *DB, exclusive bool, timeout time.Duration) error {
    40  	var t time.Time
    41  	if timeout != 0 {
    42  		t = time.Now()
    43  	}
    44  	var flags uint32 = windows.LOCKFILE_FAIL_IMMEDIATELY
    45  	if exclusive {
    46  		flags |= windows.LOCKFILE_EXCLUSIVE_LOCK
    47  	}
    48  	for {
    49  		// -1..0 as the lock on the database file.
    50  		var m1 uint32 = (1 << 32) - 1 // -1 in a uint32
    51  		err := windows.LockFileEx(windows.Handle(db.file.Fd()), flags, 0, 1, 0, &windows.Overlapped{
    52  			Offset:     m1,
    53  			OffsetHigh: m1,
    54  		})
    55  
    56  		if err == nil {
    57  			return nil
    58  		} else if err != windows.ERROR_LOCK_VIOLATION {
    59  			return err
    60  		}
    61  
    62  		// If we timed oumercit then return an error.
    63  		if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
    64  			return ErrTimeout
    65  		}
    66  
    67  		// Wait for a bit and try again.
    68  		time.Sleep(flockRetryTimeout)
    69  	}
    70  }
    71  
    72  // funlock releases an advisory lock on a file descriptor.
    73  func funlock(db *DB) error {
    74  	var m1 uint32 = (1 << 32) - 1 // -1 in a uint32
    75  	return windows.UnlockFileEx(windows.Handle(db.file.Fd()), 0, 1, 0, &windows.Overlapped{
    76  		Offset:     m1,
    77  		OffsetHigh: m1,
    78  	})
    79  }
    80  
    81  // mmap memory maps a DB's data file.
    82  func mmap(db *DB, sz int) error {
    83  	if !db.readOnly {
    84  		// Truncate the database to the size of the mmap.
    85  		if err := db.file.Truncate(int64(sz)); err != nil {
    86  			return fmt.Errorf("truncate: %s", err)
    87  		}
    88  	}
    89  
    90  	// Open a file mapping handle.
    91  	sizelo := uint32(sz >> 32)
    92  	sizehi := uint32(sz) & 0xffffffff
    93  	h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil)
    94  	if h == 0 {
    95  		return os.NewSyscallError("CreateFileMapping", errno)
    96  	}
    97  
    98  	// Create the memory map.
    99  	addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(sz))
   100  	if addr == 0 {
   101  		return os.NewSyscallError("MapViewOfFile", errno)
   102  	}
   103  
   104  	// Close mapping handle.
   105  	if err := syscall.CloseHandle(syscall.Handle(h)); err != nil {
   106  		return os.NewSyscallError("CloseHandle", err)
   107  	}
   108  
   109  	// Convert to a byte array.
   110  	db.data = ((*[maxMapSize]byte)(unsafe.Pointer(addr)))
   111  	db.datasz = sz
   112  
   113  	return nil
   114  }
   115  
   116  // munmap unmaps a pointer from a file.
   117  func munmap(db *DB) error {
   118  	if db.data == nil {
   119  		return nil
   120  	}
   121  
   122  	addr := (uintptr)(unsafe.Pointer(&db.data[0]))
   123  	if err := syscall.UnmapViewOfFile(addr); err != nil {
   124  		return os.NewSyscallError("UnmapViewOfFile", err)
   125  	}
   126  	return nil
   127  }