file.go 2.4 KB

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