...

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

Documentation: go.etcd.io/bbolt

     1  package bbolt
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"syscall"
     7  	"time"
     8  	"unsafe"
     9  
    10  	"golang.org/x/sys/windows"
    11  )
    12  
    13  // fdatasync flushes written data to a file descriptor.
    14  func fdatasync(db *DB) error {
    15  	return db.file.Sync()
    16  }
    17  
    18  // flock acquires an advisory lock on a file descriptor.
    19  func flock(db *DB, exclusive bool, timeout time.Duration) error {
    20  	var t time.Time
    21  	if timeout != 0 {
    22  		t = time.Now()
    23  	}
    24  	var flags uint32 = windows.LOCKFILE_FAIL_IMMEDIATELY
    25  	if exclusive {
    26  		flags |= windows.LOCKFILE_EXCLUSIVE_LOCK
    27  	}
    28  	for {
    29  		// Fix for https://github.com/etcd-io/bbolt/issues/121. Use byte-range
    30  		// -1..0 as the lock on the database file.
    31  		var m1 uint32 = (1 << 32) - 1 // -1 in a uint32
    32  		err := windows.LockFileEx(windows.Handle(db.file.Fd()), flags, 0, 1, 0, &windows.Overlapped{
    33  			Offset:     m1,
    34  			OffsetHigh: m1,
    35  		})
    36  
    37  		if err == nil {
    38  			return nil
    39  		} else if err != windows.ERROR_LOCK_VIOLATION {
    40  			return err
    41  		}
    42  
    43  		// If we timed oumercit then return an error.
    44  		if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
    45  			return ErrTimeout
    46  		}
    47  
    48  		// Wait for a bit and try again.
    49  		time.Sleep(flockRetryTimeout)
    50  	}
    51  }
    52  
    53  // funlock releases an advisory lock on a file descriptor.
    54  func funlock(db *DB) error {
    55  	var m1 uint32 = (1 << 32) - 1 // -1 in a uint32
    56  	return windows.UnlockFileEx(windows.Handle(db.file.Fd()), 0, 1, 0, &windows.Overlapped{
    57  		Offset:     m1,
    58  		OffsetHigh: m1,
    59  	})
    60  }
    61  
    62  // mmap memory maps a DB's data file.
    63  // Based on: https://github.com/edsrzf/mmap-go
    64  func mmap(db *DB, sz int) error {
    65  	var sizelo, sizehi uint32
    66  
    67  	if !db.readOnly {
    68  		// Truncate the database to the size of the mmap.
    69  		if err := db.file.Truncate(int64(sz)); err != nil {
    70  			return fmt.Errorf("truncate: %s", err)
    71  		}
    72  		sizehi = uint32(sz >> 32)
    73  		sizelo = uint32(sz) & 0xffffffff
    74  	}
    75  
    76  	// Open a file mapping handle.
    77  	h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizehi, sizelo, nil)
    78  	if h == 0 {
    79  		return os.NewSyscallError("CreateFileMapping", errno)
    80  	}
    81  
    82  	// Create the memory map.
    83  	addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, 0)
    84  	if addr == 0 {
    85  		// Do our best and report error returned from MapViewOfFile.
    86  		_ = syscall.CloseHandle(h)
    87  		return os.NewSyscallError("MapViewOfFile", errno)
    88  	}
    89  
    90  	// Close mapping handle.
    91  	if err := syscall.CloseHandle(syscall.Handle(h)); err != nil {
    92  		return os.NewSyscallError("CloseHandle", err)
    93  	}
    94  
    95  	// Convert to a byte array.
    96  	db.data = ((*[maxMapSize]byte)(unsafe.Pointer(addr)))
    97  	db.datasz = sz
    98  
    99  	return nil
   100  }
   101  
   102  // munmap unmaps a pointer from a file.
   103  // Based on: https://github.com/edsrzf/mmap-go
   104  func munmap(db *DB) error {
   105  	if db.data == nil {
   106  		return nil
   107  	}
   108  
   109  	addr := (uintptr)(unsafe.Pointer(&db.data[0]))
   110  	var err1 error
   111  	if err := syscall.UnmapViewOfFile(addr); err != nil {
   112  		err1 = os.NewSyscallError("UnmapViewOfFile", err)
   113  	}
   114  	db.data = nil
   115  	db.datasz = 0
   116  	return err1
   117  }
   118  

View as plain text