github.com/chrislusf/greenpack@v3.7.1-0.20170911073826-ad5bd10b7c47+incompatible/msgp/file.go (about)

     1  // +build linux,!appengine darwin dragonfly freebsd netbsd openbsd
     2  
     3  package msgp
     4  
     5  import (
     6  	"os"
     7  	"syscall"
     8  )
     9  
    10  // ReadFile reads a file into 'dst' using
    11  // a read-only memory mapping. Consequently,
    12  // the file must be mmap-able, and the
    13  // Unmarshaler should never write to
    14  // the source memory. (Methods generated
    15  // by the msgp tool obey that constraint, but
    16  // user-defined implementations may not.)
    17  //
    18  // Reading and writing through file mappings
    19  // is only efficient for large files; small
    20  // files are best read and written using
    21  // the ordinary streaming interfaces.
    22  //
    23  func ReadFile(dst Unmarshaler, file *os.File) error {
    24  	stat, err := file.Stat()
    25  	if err != nil {
    26  		return err
    27  	}
    28  	data, err := syscall.Mmap(int(file.Fd()), 0, int(stat.Size()), syscall.PROT_READ, syscall.MAP_SHARED)
    29  	if err != nil {
    30  		return err
    31  	}
    32  	adviseRead(data)
    33  	_, err = dst.UnmarshalMsg(data)
    34  	uerr := syscall.Munmap(data)
    35  	if err == nil {
    36  		err = uerr
    37  	}
    38  	return err
    39  }
    40  
    41  // MarshalSizer is the combination
    42  // of the Marshaler and Sizer
    43  // interfaces.
    44  type MarshalSizer interface {
    45  	Marshaler
    46  	Sizer
    47  }
    48  
    49  // WriteFile writes a file from 'src' using
    50  // memory mapping. It overwrites the entire
    51  // contents of the previous file.
    52  // The mapping size is calculated
    53  // using the `Msgsize()` method
    54  // of 'src', so it must produce a result
    55  // equal to or greater than the actual encoded
    56  // size of the object. Otherwise,
    57  // a fault (SIGBUS) will occur.
    58  //
    59  // Reading and writing through file mappings
    60  // is only efficient for large files; small
    61  // files are best read and written using
    62  // the ordinary streaming interfaces.
    63  //
    64  // NOTE: The performance of this call
    65  // is highly OS- and filesystem-dependent.
    66  // Users should take care to test that this
    67  // performs as expected in a production environment.
    68  // (Linux users should run a kernel and filesystem
    69  // that support fallocate(2) for the best results.)
    70  func WriteFile(src MarshalSizer, file *os.File) error {
    71  	sz := src.Msgsize()
    72  	err := fallocate(file, int64(sz))
    73  	if err != nil {
    74  		return err
    75  	}
    76  	data, err := syscall.Mmap(int(file.Fd()), 0, sz, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
    77  	if err != nil {
    78  		return err
    79  	}
    80  	adviseWrite(data)
    81  	chunk := data[:0]
    82  	chunk, err = src.MarshalMsg(chunk)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	uerr := syscall.Munmap(data)
    87  	if uerr != nil {
    88  		return uerr
    89  	}
    90  	return file.Truncate(int64(len(chunk)))
    91  }