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 }