From c2577db1c22e0bb64ea3df16e9424e6dce1d55ab Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Wed, 11 Jun 2014 11:11:21 -0600 Subject: [PATCH] Add Windows support. --- bolt.go | 13 ----------- bolt_darwin.go | 33 +++++++++++++++++++++++++++ bolt_linux.go | 21 +++++++++++++++++ bolt_windows.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ db.go | 14 +++++++----- 5 files changed, 123 insertions(+), 18 deletions(-) delete mode 100644 bolt.go create mode 100644 bolt_darwin.go create mode 100644 bolt_windows.go diff --git a/bolt.go b/bolt.go deleted file mode 100644 index a3f1eac..0000000 --- a/bolt.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build !linux - -package bolt - -import ( - "os" -) - -var odirect int - -func fdatasync(f *os.File) error { - return f.Sync() -} diff --git a/bolt_darwin.go b/bolt_darwin.go new file mode 100644 index 0000000..557de72 --- /dev/null +++ b/bolt_darwin.go @@ -0,0 +1,33 @@ +package bolt + +import ( + "os" + "syscall" +) + +var odirect int + +// fdatasync flushes written data to a file descriptor. +func fdatasync(f *os.File) error { + return f.Sync() +} + +// flock acquires an advisory lock on a file descriptor. +func flock(f *os.File) error { + return syscall.Flock(int(f.Fd()), syscall.LOCK_EX) +} + +// funlock releases an advisory lock on a file descriptor. +func funlock(f *os.File) error { + return syscall.Flock(int(f.Fd()), syscall.LOCK_UN) +} + +// mmap memory maps a file to a byte slice. +func mmap(f *os.File, sz int) ([]byte, error) { + return syscall.Mmap(int(f.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED) +} + +// munmap unmaps a pointer from a file. +func munmap(b []byte) error { + return syscall.Munmap(b) +} diff --git a/bolt_linux.go b/bolt_linux.go index 4351db5..9aba955 100644 --- a/bolt_linux.go +++ b/bolt_linux.go @@ -7,6 +7,27 @@ import ( var odirect = syscall.O_DIRECT +// fdatasync flushes written data to a file descriptor. func fdatasync(f *os.File) error { return syscall.Fdatasync(int(f.Fd())) } + +// flock acquires an advisory lock on a file descriptor. +func flock(f *os.File) error { + return syscall.Flock(int(f.Fd()), syscall.LOCK_EX) +} + +// funlock releases an advisory lock on a file descriptor. +func funlock(f *os.File) error { + return syscall.Flock(int(f.Fd()), syscall.LOCK_UN) +} + +// mmap memory maps a file to a byte slice. +func mmap(f *os.File, sz int) ([]byte, error) { + return syscall.Mmap(int(f.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED) +} + +// munmap unmaps a pointer from a file. +func munmap(b []byte) error { + return syscall.Munmap(b) +} diff --git a/bolt_windows.go b/bolt_windows.go new file mode 100644 index 0000000..9962f03 --- /dev/null +++ b/bolt_windows.go @@ -0,0 +1,60 @@ +package bolt + +import ( + "os" + "syscall" + "unsafe" +) + +var odirect int + +// fdatasync flushes written data to a file descriptor. +func fdatasync(f *os.File) error { + return f.Sync() +} + +// flock acquires an advisory lock on a file descriptor. +func flock(f *os.File) error { + return nil +} + +// funlock releases an advisory lock on a file descriptor. +func funlock(f *os.File) error { + return nil +} + +// mmap memory maps a file to a byte slice. +// Based on: https://github.com/edsrzf/mmap-go +func mmap(f *os.File, sz int) ([]byte, error) { + // Open a file mapping handle. + sizelo, sizehi := uint32(sz>>32), uint32(sz&0xffffffff) + h, errno := syscall.CreateFileMapping(syscall.Handle(f.Fd()), nil, syscall.PAGE_READONLY, sizehi, sizelo, nil) + if h == 0 { + return nil, os.NewSyscallError("CreateFileMapping", errno) + } + + // Create the memory map. + addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(sz)) + if addr == 0 { + return nil, os.NewSyscallError("MapViewOfFile", errno) + } + + // Close mapping handle. + if err := syscall.CloseHandle(syscall.Handle(h)); err != nil { + return nil, os.NewSyscallError("CloseHandle", err) + } + + // Convert to a byte slice. + b := ((*[0xFFFFFFF]byte)(unsafe.Pointer(addr)))[0:sz] + return b, nil +} + +// munmap unmaps a pointer from a file. +// Based on: https://github.com/edsrzf/mmap-go +func munmap(b []byte) error { + addr := (uintptr)(unsafe.Pointer(&b[0])) + if err := syscall.UnmapViewOfFile(addr); err != nil { + return os.NewSyscallError("UnmapViewOfFile", err) + } + return nil +} diff --git a/db.go b/db.go index d759b1b..2132f9c 100644 --- a/db.go +++ b/db.go @@ -6,7 +6,6 @@ import ( "hash/fnv" "os" "sync" - "syscall" "unsafe" ) @@ -120,7 +119,7 @@ func Open(path string, mode os.FileMode) (*DB, error) { // Lock file so that other processes using Bolt cannot use the database // at the same time. This would cause corruption since the two processes // would write meta pages and free pages separately. - if err := syscall.Flock(int(db.file.Fd()), syscall.LOCK_EX); err != nil { + if err := flock(db.file); err != nil { _ = db.close() return nil, err } @@ -192,8 +191,13 @@ func (db *DB) mmap(minsz int) error { } size = db.mmapSize(size) + // Truncate the database to the size of the mmap. + if err := db.file.Truncate(int64(size)); err != nil { + return fmt.Errorf("truncate: %s", err) + } + // Memory-map the data file as a byte slice. - if db.data, err = syscall.Mmap(int(db.file.Fd()), 0, size, syscall.PROT_READ, syscall.MAP_SHARED); err != nil { + if db.data, err = mmap(db.file, size); err != nil { return err } @@ -215,7 +219,7 @@ func (db *DB) mmap(minsz int) error { // munmap unmaps the data file from memory. func (db *DB) munmap() error { if db.data != nil { - if err := syscall.Munmap(db.data); err != nil { + if err := munmap(db.data); err != nil { return fmt.Errorf("unmap error: " + err.Error()) } db.data = nil @@ -314,7 +318,7 @@ func (db *DB) close() error { // Close file handles. if db.file != nil { // Unlock the file. - _ = syscall.Flock(int(db.file.Fd()), syscall.LOCK_UN) + _ = funlock(db.file) // Close the file descriptor. if err := db.file.Close(); err != nil {