Codebase list golang-github-boltdb-bolt / 1c97a49
Add Windows support. This commit adds Windows support to Bolt. Windows memory maps return an address instead of a byte slice so the DB.data field had to be refactored to be a pointer to a large byte array. Ben Johnson 9 years ago
7 changed file(s) with 97 addition(s) and 41 deletion(s). Raw diff Collapse all Expand all
0 package bolt
1
2 // maxMapSize represents the largest mmap size supported by Bolt.
3 const maxMapSize = 0xFFFFFFF // 256MB
0 package bolt
1
2 // maxMapSize represents the largest mmap size supported by Bolt.
3 const maxMapSize = 0xFFFFFFFFFFFF // 256TB
22 import (
33 "os"
44 "syscall"
5 "unsafe"
56 )
67
78 var odirect int
2122 return syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
2223 }
2324
24 // mmap memory maps a file to a byte slice.
25 func mmap(f *os.File, sz int) ([]byte, error) {
26 return syscall.Mmap(int(f.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED)
25 // mmap memory maps a DB's data file.
26 func mmap(db *DB, sz int) error {
27 b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED)
28 if err != nil {
29 return err
30 }
31
32 // Save the original byte slice and convert to a byte array pointer.
33 db.dataref = b
34 db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
35 db.datasz = sz
36 return nil
2737 }
2838
29 // munmap unmaps a pointer from a file.
30 func munmap(b []byte) error {
31 return syscall.Munmap(b)
39 // munmap unmaps a DB's data file from memory.
40 func munmap(db *DB) error {
41 // Ignore the unmap if we have no mapped data.
42 if db.dataref == nil {
43 return nil
44 }
45
46 // Unmap using the original byte slice.
47 err := syscall.Munmap(db.dataref)
48 db.dataref = nil
49 db.data = nil
50 db.datasz = 0
51 return err
3252 }
22 import (
33 "os"
44 "syscall"
5 "unsafe"
56 )
67
78 var odirect = syscall.O_DIRECT
2122 return syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
2223 }
2324
24 // mmap memory maps a file to a byte slice.
25 func mmap(f *os.File, sz int) ([]byte, error) {
26 return syscall.Mmap(int(f.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED)
25 // mmap memory maps a DB's data file.
26 func mmap(db *DB, sz int) error {
27 b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED)
28 if err != nil {
29 return err
30 }
31
32 // Save the original byte slice and convert to a byte array pointer.
33 db.dataref = b
34 db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
35 db.datasz = sz
36 return nil
2737 }
2838
29 // munmap unmaps a pointer from a file.
30 func munmap(b []byte) error {
31 return syscall.Munmap(b)
39 // munmap unmaps a DB's data file from memory.
40 func munmap(db *DB) error {
41 // Ignore the unmap if we have no mapped data.
42 if db.dataref == nil {
43 return nil
44 }
45
46 // Unmap using the original byte slice.
47 err := syscall.Munmap(db.dataref)
48 db.dataref = nil
49 db.data = nil
50 db.datasz = 0
51 return err
3252 }
00 package bolt
11
22 import (
3 "fmt"
34 "os"
45 "syscall"
56 "unsafe"
2223 return nil
2324 }
2425
25 // mmap memory maps a file to a byte slice.
26 // mmap memory maps a DB's data file.
2627 // Based on: https://github.com/edsrzf/mmap-go
27 func mmap(f *os.File, sz int) ([]byte, error) {
28 func mmap(db *DB, sz int) error {
29 // Truncate the database to the size of the mmap.
30 if err := db.file.Truncate(int64(sz)); err != nil {
31 return fmt.Errorf("truncate: %s", err)
32 }
33
2834 // Open a file mapping handle.
29 sizelo, sizehi := uint32(sz>>32), uint32(sz&0xffffffff)
30 h, errno := syscall.CreateFileMapping(syscall.Handle(f.Fd()), nil, syscall.PAGE_READONLY, sizehi, sizelo, nil)
35 sizelo := uint32(sz >> 32)
36 sizehi := uint32(sz & 0xffffffff)
37 h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil)
3138 if h == 0 {
32 return nil, os.NewSyscallError("CreateFileMapping", errno)
39 return os.NewSyscallError("CreateFileMapping", errno)
3340 }
3441
3542 // Create the memory map.
3643 addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(sz))
3744 if addr == 0 {
38 return nil, os.NewSyscallError("MapViewOfFile", errno)
45 return os.NewSyscallError("MapViewOfFile", errno)
3946 }
4047
4148 // Close mapping handle.
4249 if err := syscall.CloseHandle(syscall.Handle(h)); err != nil {
43 return nil, os.NewSyscallError("CloseHandle", err)
50 return os.NewSyscallError("CloseHandle", err)
4451 }
4552
46 // Convert to a byte slice.
47 b := ((*[0xFFFFFFF]byte)(unsafe.Pointer(addr)))[0:sz]
48 return b, nil
53 // Convert to a byte array.
54 db.data = ((*[maxMapSize]byte)(unsafe.Pointer(addr)))
55 db.datasz = sz
56
57 return nil
4958 }
5059
5160 // munmap unmaps a pointer from a file.
5261 // Based on: https://github.com/edsrzf/mmap-go
53 func munmap(b []byte) error {
54 addr := (uintptr)(unsafe.Pointer(&b[0]))
62 func munmap(db *DB) error {
63 if db.data == nil {
64 return nil
65 }
66
67 addr := (uintptr)(unsafe.Pointer(&db.data[0]))
5568 if err := syscall.UnmapViewOfFile(addr); err != nil {
5669 return os.NewSyscallError("UnmapViewOfFile", err)
5770 }
6666
6767 path string
6868 file *os.File
69 data []byte
69 dataref []byte
70 data *[maxMapSize]byte
71 datasz int
7072 meta0 *meta
7173 meta1 *meta
7274 pageSize int
190192 }
191193 size = db.mmapSize(size)
192194
193 // Truncate the database to the size of the mmap.
194 if err := db.file.Truncate(int64(size)); err != nil {
195 return fmt.Errorf("truncate: %s", err)
196 }
197
198195 // Memory-map the data file as a byte slice.
199 if db.data, err = mmap(db.file, size); err != nil {
196 if err := mmap(db, size); err != nil {
200197 return err
201198 }
202199
217214
218215 // munmap unmaps the data file from memory.
219216 func (db *DB) munmap() error {
220 if db.data != nil {
221 if err := munmap(db.data); err != nil {
222 return fmt.Errorf("unmap error: " + err.Error())
223 }
224 db.data = nil
217 if err := munmap(db); err != nil {
218 return fmt.Errorf("unmap error: " + err.Error())
225219 }
226220 return nil
227221 }
506500 // This is for internal access to the raw data bytes from the C cursor, use
507501 // carefully, or not at all.
508502 func (db *DB) Info() *Info {
509 return &Info{db.data, db.pageSize}
503 return &Info{uintptr(unsafe.Pointer(&db.data[0])), db.pageSize}
510504 }
511505
512506 // page retrieves a page reference from the mmap based on the current page size.
543537 // Resize mmap() if we're at the end.
544538 p.id = db.rwtx.meta.pgid
545539 var minsz = int((p.id+pgid(count))+1) * db.pageSize
546 if minsz >= len(db.data) {
540 if minsz >= db.datasz {
547541 if err := db.mmap(minsz); err != nil {
548542 return nil, fmt.Errorf("mmap allocate error: %s", err)
549543 }
578572 }
579573
580574 type Info struct {
581 Data []byte
575 Data uintptr
582576 PageSize int
583577 }
584578
1010 rolled back in the event of a crash.
1111
1212 The design of Bolt is based on Howard Chu's LMDB database project.
13
14 Bolt currently works on Windows, Mac OS X, and Linux.
15
1316
1417 Basics
1518
3235 will cause Go to panic. If you need to work with data returned from a Get() you
3336 need to first copy it to a new byte slice.
3437
35 Bolt currently works on Mac OS and Linux. Windows support is coming soon.
36
3738 */
3839 package bolt