123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- //go:build (linux || darwin || dragonfly || freebsd || netbsd || openbsd) && !appengine && !tinygo
- // +build linux darwin dragonfly freebsd netbsd openbsd
- // +build !appengine
- // +build !tinygo
- package msgp
- import (
- "os"
- "syscall"
- )
- // ReadFile reads a file into 'dst' using
- // a read-only memory mapping. Consequently,
- // the file must be mmap-able, and the
- // Unmarshaler should never write to
- // the source memory. (Methods generated
- // by the msgp tool obey that constraint, but
- // user-defined implementations may not.)
- //
- // Reading and writing through file mappings
- // is only efficient for large files; small
- // files are best read and written using
- // the ordinary streaming interfaces.
- func ReadFile(dst Unmarshaler, file *os.File) error {
- stat, err := file.Stat()
- if err != nil {
- return err
- }
- data, err := syscall.Mmap(int(file.Fd()), 0, int(stat.Size()), syscall.PROT_READ, syscall.MAP_SHARED)
- if err != nil {
- return err
- }
- adviseRead(data)
- _, err = dst.UnmarshalMsg(data)
- uerr := syscall.Munmap(data)
- if err == nil {
- err = uerr
- }
- return err
- }
- // MarshalSizer is the combination
- // of the Marshaler and Sizer
- // interfaces.
- type MarshalSizer interface {
- Marshaler
- Sizer
- }
- // WriteFile writes a file from 'src' using
- // memory mapping. It overwrites the entire
- // contents of the previous file.
- // The mapping size is calculated
- // using the `Msgsize()` method
- // of 'src', so it must produce a result
- // equal to or greater than the actual encoded
- // size of the object. Otherwise,
- // a fault (SIGBUS) will occur.
- //
- // Reading and writing through file mappings
- // is only efficient for large files; small
- // files are best read and written using
- // the ordinary streaming interfaces.
- //
- // NOTE: The performance of this call
- // is highly OS- and filesystem-dependent.
- // Users should take care to test that this
- // performs as expected in a production environment.
- // (Linux users should run a kernel and filesystem
- // that support fallocate(2) for the best results.)
- func WriteFile(src MarshalSizer, file *os.File) error {
- sz := src.Msgsize()
- err := fallocate(file, int64(sz))
- if err != nil {
- return err
- }
- data, err := syscall.Mmap(int(file.Fd()), 0, sz, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
- if err != nil {
- return err
- }
- adviseWrite(data)
- chunk := data[:0]
- chunk, err = src.MarshalMsg(chunk)
- if err != nil {
- return err
- }
- uerr := syscall.Munmap(data)
- if uerr != nil {
- return uerr
- }
- return file.Truncate(int64(len(chunk)))
- }
|