From 1eefa2fe2e9740243be4b09ee9c9d6c01749cb1c Mon Sep 17 00:00:00 2001 From: Mustafa Elbehery Date: Thu, 30 Nov 2023 19:55:06 +0100 Subject: [PATCH] add plan9 support --- bolt_plan9.go | 119 +++++++++++++++++++++++++++++++++++++++++++++++++ mlock_plan9.go | 11 +++++ mlock_unix.go | 4 +- 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 bolt_plan9.go create mode 100644 mlock_plan9.go diff --git a/bolt_plan9.go b/bolt_plan9.go new file mode 100644 index 000000000..faf9f3fd1 --- /dev/null +++ b/bolt_plan9.go @@ -0,0 +1,119 @@ +package bbolt + +import ( + "fmt" + "os" + "syscall" + "time" + "unsafe" + + "golang.org/x/sys/plan9" + + "go.etcd.io/bbolt/errors" +) + +// fdatasync flushes written data to a file descriptor. +func fdatasync(db *DB) error { + return db.file.Sync() +} + +// flock acquires an advisory lock on a file descriptor. +func flock(db *DB, exclusive bool, timeout time.Duration) error { + var t time.Time + if timeout != 0 { + t = time.Now() + } + var flags uint32 = plan9.LOCKFILE_FAIL_IMMEDIATELY + if exclusive { + flags |= plan9.LOCKFILE_EXCLUSIVE_LOCK + } + for { + // Fix for https://github.com/etcd-io/bbolt/issues/121. Use byte-range + // -1..0 as the lock on the database file. + var m1 uint32 = (1 << 32) - 1 // -1 in a uint32 + err := plan9.LockFileEx(plan9.Handle(db.file.Fd()), flags, 0, 1, 0, &plan9.Overlapped{ + Offset: m1, + OffsetHigh: m1, + }) + + if err == nil { + return nil + } else if err != plan9.ERROR_LOCK_VIOLATION { + return err + } + + // If we timed oumercit then return an error. + if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout { + return errors.ErrTimeout + } + + // Wait for a bit and try again. + time.Sleep(flockRetryTimeout) + } +} + +// funlock releases an advisory lock on a file descriptor. +func funlock(db *DB) error { + var m1 uint32 = (1 << 32) - 1 // -1 in a uint32 + return plan9.UnlockFileEx(plan9.Handle(db.file.Fd()), 0, 1, 0, &plan9.Overlapped{ + Offset: m1, + OffsetHigh: m1, + }) +} + +// mmap memory maps a DB's data file. +// Based on: https://github.com/edsrzf/mmap-go +func mmap(db *DB, sz int) error { + var sizelo, sizehi uint32 + + if !db.readOnly { + // Truncate the database to the size of the mmap. + if err := db.file.Truncate(int64(sz)); err != nil { + return fmt.Errorf("truncate: %s", err) + } + sizehi = uint32(sz >> 32) + sizelo = uint32(sz) + } + + // Open a file mapping handle. + h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizehi, sizelo, nil) + if h == 0 { + return os.NewSyscallError("CreateFileMapping", errno) + } + + // Create the memory map. + addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, 0) + if addr == 0 { + // Do our best and report error returned from MapViewOfFile. + _ = syscall.CloseHandle(h) + return os.NewSyscallError("MapViewOfFile", errno) + } + + // Close mapping handle. + if err := syscall.CloseHandle(syscall.Handle(h)); err != nil { + return os.NewSyscallError("CloseHandle", err) + } + + // Convert to a byte array. + db.data = (*[maxMapSize]byte)(unsafe.Pointer(addr)) + db.datasz = sz + + return nil +} + +// munmap unmaps a pointer from a file. +// Based on: https://github.com/edsrzf/mmap-go +func munmap(db *DB) error { + if db.data == nil { + return nil + } + + addr := (uintptr)(unsafe.Pointer(&db.data[0])) + var err1 error + if err := syscall.UnmapViewOfFile(addr); err != nil { + err1 = os.NewSyscallError("UnmapViewOfFile", err) + } + db.data = nil + db.datasz = 0 + return err1 +} diff --git a/mlock_plan9.go b/mlock_plan9.go new file mode 100644 index 000000000..00b0fb431 --- /dev/null +++ b/mlock_plan9.go @@ -0,0 +1,11 @@ +package bbolt + +// mlock locks memory of db file +func mlock(_ *DB, _ int) error { + panic("mlock is supported only on UNIX systems") +} + +// munlock unlocks memory of db file +func munlock(_ *DB, _ int) error { + panic("munlock is supported only on UNIX systems") +} diff --git a/mlock_unix.go b/mlock_unix.go index 744a972f5..78fc6a890 100644 --- a/mlock_unix.go +++ b/mlock_unix.go @@ -1,5 +1,5 @@ -//go:build !windows -// +build !windows +//go:build !windows && !plan9 +// +build !windows,!plan9 package bbolt