github.com/m3db/m3@v1.5.0/src/x/mmap/mmap.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package mmap 22 23 import ( 24 "fmt" 25 "os" 26 27 xerrors "github.com/m3db/m3/src/x/errors" 28 ) 29 30 // FileOpener is the signature of a function that MmapFiles can use 31 // to open files 32 type FileOpener func(filePath string) (*os.File, error) 33 34 // Package-level global for easy mocking 35 var mmapFdFn = Fd 36 37 // FileDesc contains the fields required for Mmaping a file using MmapFiles 38 type FileDesc struct { 39 // file is the *os.File ref to store 40 File **os.File 41 // bytes is the []byte slice ref to store the mmap'd address 42 Descriptor *Descriptor 43 // options specifies options to use when mmaping a file 44 Options Options 45 } 46 47 // Options contains the options for mmap'ing a file 48 type Options struct { 49 // read is whether to make mmap bytes ref readable 50 Read bool 51 // write is whether to make mmap bytes ref writable 52 Write bool 53 // hugeTLB is the mmap huge TLB options 54 HugeTLB HugeTLBOptions 55 // ReporterOptions is the reporter options 56 ReporterOptions ReporterOptions 57 } 58 59 // Descriptor is a descriptor of a successful mmap 60 type Descriptor struct { 61 Bytes []byte 62 Warning error 63 ReporterOptions ReporterOptions 64 } 65 66 // HugeTLBOptions contains all options related to huge TLB 67 type HugeTLBOptions struct { 68 // enabled determines if using the huge TLB flag is enabled for platforms 69 // that support it 70 Enabled bool 71 // threshold determines if the size being mmap'd is greater or equal 72 // to this value to use or not use the huge TLB flag if enabled 73 Threshold int64 74 } 75 76 // ReporterOptions contains all options to tracking mmap calls 77 type ReporterOptions struct { 78 // Context is the context to report to reporter for this 79 Context Context 80 // Reporter if set will receive events for reporting 81 Reporter Reporter 82 } 83 84 // Context provides context about the current mmap for reporting purposes 85 type Context struct { 86 Size int64 87 Name string 88 Metadata map[string]string 89 } 90 91 // Reporter implements the reporting of mmap. 92 type Reporter interface { 93 // ReportMap reports the mapping of an mmap and allows an error to be 94 // returned in case the reporter want's to deny allowing this map call. 95 ReportMap(ctx Context) error 96 // ReportUnmap reports the unmapping of an mmap and allows an error to be 97 // returned in case the reporter want's to deny allowing this unmap call. 98 ReportUnmap(ctx Context) error 99 } 100 101 // FilesResult contains the result of calling MmapFiles 102 type FilesResult struct { 103 Warning error 104 } 105 106 // Files is a utility function for mmap'ing a group of files at once 107 func Files(opener FileOpener, files map[string]FileDesc) (FilesResult, error) { 108 multiWarn := xerrors.NewMultiError() 109 multiErr := xerrors.NewMultiError() 110 111 for filePath, fileDesc := range files { 112 fd, err := opener(filePath) 113 if err != nil { 114 multiErr = multiErr.Add(errorWithFilename(filePath, err)) 115 break 116 } 117 118 desc, err := File(fd, fileDesc.Options) 119 if err != nil { 120 multiErr = multiErr.Add(errorWithFilename(filePath, err)) 121 break 122 } 123 if desc.Warning != nil { 124 multiWarn = multiWarn.Add(errorWithFilename(filePath, desc.Warning)) 125 } 126 127 *fileDesc.File = fd 128 *fileDesc.Descriptor = desc 129 } 130 131 if multiErr.FinalError() == nil { 132 return FilesResult{Warning: multiWarn.FinalError()}, nil 133 } 134 135 // If we have encountered an error when opening the files, 136 // close the ones that have been opened. 137 for filePath, fileDesc := range files { 138 if *fileDesc.File != nil { 139 multiErr = multiErr.Add(errorWithFilename(filePath, (*fileDesc.File).Close())) 140 } 141 if fileDesc.Descriptor != nil { 142 multiErr = multiErr.Add(errorWithFilename(filePath, Munmap(*fileDesc.Descriptor))) 143 } 144 } 145 146 return FilesResult{Warning: multiWarn.FinalError()}, multiErr.FinalError() 147 } 148 149 // File mmap's a file 150 func File(file *os.File, opts Options) (Descriptor, error) { 151 name := file.Name() 152 stat, err := os.Stat(name) 153 if err != nil { 154 return Descriptor{}, fmt.Errorf("mmap file could not stat %s: %v", name, err) 155 } 156 if stat.IsDir() { 157 return Descriptor{}, fmt.Errorf("mmap target is directory: %s", name) 158 } 159 return mmapFdFn(int64(file.Fd()), 0, stat.Size(), opts) 160 } 161 162 func errorWithFilename(name string, err error) error { 163 if err == nil { 164 return nil 165 } 166 return fmt.Errorf("file %s encountered err: %s", name, err.Error()) 167 }