相关概念
Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error)
- prot:内存保护标志位,可以通过或运算符`|`组合
- PROT_EXEC
- PROT_READ
- PROT_WRITE
- PROT_NONE
- flags:映射对象的类型,常用的是以下两类
- MAP_SHARED
- MAP_PRIVATE
代码
package mmap
import (
"fmt"
"os"
"syscall"
"unsafe"
)
const maxMapSize int = 0xFFFFFFFFFFFF
type DB struct {
file *os.File
dataref []byte
data *[maxMapSize]byte
datasz int
}
func mmap(db *DB, sz int) error {
b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
if err != nil {
return err
}
if err := madvise(b, syscall.MADV_RANDOM); err != nil {
return fmt.Errorf("madvise: %s", err)
}
db.dataref = b
db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
db.datasz = sz
return nil
}
func munmap(db *DB) error {
if db.dataref == nil {
return nil
}
err := syscall.Munmap(db.dataref)
db.dataref = nil
db.data = nil
db.datasz = 0
return err
}
func madvise(b []byte, advice int) (err error) {
_, _, e1 := syscall.Syscall(syscall.SYS_MADVISE, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), uintptr(advice))
if e1 != 0 {
err = e1
}
return
}
func (d *DB) grow(size int64) {
if info, _ := d.file.Stat(); info.Size() >= size {
return
}
if err := d.file.Truncate(size); err != nil {
panic(err)
}
}
测试用例
package mmap
import (
"fmt"
"os"
"testing"
)
func TestMmap(t *testing.T) {
f, err := os.OpenFile("./tmp.txt", os.O_CREATE|os.O_RDWR, 0644)
if err != nil {
panic(err)
}
db := &DB{file: f}
err = mmap(db, 1<<10)
if err != nil {
panic(err)
}
msg := []byte("hello,world1234")
sz := int64(len(msg))
db.grow(sz)
for i := 0; i < len(msg); i++ {
db.data[i] = msg[i]
}
fmt.Println(string(db.data[:sz]))
munmap(db)
}
文件中结果如下
>>> cat tmp.txt
>>> hello,world1234%