Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / boltdb / bolt / bolt_windows.go
1 package bolt
2
3 import (
4         "fmt"
5         "os"
6         "syscall"
7         "time"
8         "unsafe"
9 )
10
11 // LockFileEx code derived from golang build filemutex_windows.go @ v1.5.1
12 var (
13         modkernel32      = syscall.NewLazyDLL("kernel32.dll")
14         procLockFileEx   = modkernel32.NewProc("LockFileEx")
15         procUnlockFileEx = modkernel32.NewProc("UnlockFileEx")
16 )
17
18 const (
19         lockExt = ".lock"
20
21         // see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
22         flagLockExclusive       = 2
23         flagLockFailImmediately = 1
24
25         // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
26         errLockViolation syscall.Errno = 0x21
27 )
28
29 func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
30         r, _, err := procLockFileEx.Call(uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)))
31         if r == 0 {
32                 return err
33         }
34         return nil
35 }
36
37 func unlockFileEx(h syscall.Handle, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
38         r, _, err := procUnlockFileEx.Call(uintptr(h), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)), 0)
39         if r == 0 {
40                 return err
41         }
42         return nil
43 }
44
45 // fdatasync flushes written data to a file descriptor.
46 func fdatasync(db *DB) error {
47         return db.file.Sync()
48 }
49
50 // flock acquires an advisory lock on a file descriptor.
51 func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
52         // Create a separate lock file on windows because a process
53         // cannot share an exclusive lock on the same file. This is
54         // needed during Tx.WriteTo().
55         f, err := os.OpenFile(db.path+lockExt, os.O_CREATE, mode)
56         if err != nil {
57                 return err
58         }
59         db.lockfile = f
60
61         var t time.Time
62         for {
63                 // If we're beyond our timeout then return an error.
64                 // This can only occur after we've attempted a flock once.
65                 if t.IsZero() {
66                         t = time.Now()
67                 } else if timeout > 0 && time.Since(t) > timeout {
68                         return ErrTimeout
69                 }
70
71                 var flag uint32 = flagLockFailImmediately
72                 if exclusive {
73                         flag |= flagLockExclusive
74                 }
75
76                 err := lockFileEx(syscall.Handle(db.lockfile.Fd()), flag, 0, 1, 0, &syscall.Overlapped{})
77                 if err == nil {
78                         return nil
79                 } else if err != errLockViolation {
80                         return err
81                 }
82
83                 // Wait for a bit and try again.
84                 time.Sleep(50 * time.Millisecond)
85         }
86 }
87
88 // funlock releases an advisory lock on a file descriptor.
89 func funlock(db *DB) error {
90         err := unlockFileEx(syscall.Handle(db.lockfile.Fd()), 0, 1, 0, &syscall.Overlapped{})
91         db.lockfile.Close()
92         os.Remove(db.path+lockExt)
93         return err
94 }
95
96 // mmap memory maps a DB's data file.
97 // Based on: https://github.com/edsrzf/mmap-go
98 func mmap(db *DB, sz int) error {
99         if !db.readOnly {
100                 // Truncate the database to the size of the mmap.
101                 if err := db.file.Truncate(int64(sz)); err != nil {
102                         return fmt.Errorf("truncate: %s", err)
103                 }
104         }
105
106         // Open a file mapping handle.
107         sizelo := uint32(sz >> 32)
108         sizehi := uint32(sz) & 0xffffffff
109         h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil)
110         if h == 0 {
111                 return os.NewSyscallError("CreateFileMapping", errno)
112         }
113
114         // Create the memory map.
115         addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(sz))
116         if addr == 0 {
117                 return os.NewSyscallError("MapViewOfFile", errno)
118         }
119
120         // Close mapping handle.
121         if err := syscall.CloseHandle(syscall.Handle(h)); err != nil {
122                 return os.NewSyscallError("CloseHandle", err)
123         }
124
125         // Convert to a byte array.
126         db.data = ((*[maxMapSize]byte)(unsafe.Pointer(addr)))
127         db.datasz = sz
128
129         return nil
130 }
131
132 // munmap unmaps a pointer from a file.
133 // Based on: https://github.com/edsrzf/mmap-go
134 func munmap(db *DB) error {
135         if db.data == nil {
136                 return nil
137         }
138
139         addr := (uintptr)(unsafe.Pointer(&db.data[0]))
140         if err := syscall.UnmapViewOfFile(addr); err != nil {
141                 return os.NewSyscallError("UnmapViewOfFile", err)
142         }
143         return nil
144 }