github.com/scottcagno/storage@v1.8.0/pkg/mmap/mmap.go (about) 1 package mmap 2 3 import ( 4 "github.com/scottcagno/storage/pkg/mmap/segment" 5 "io" 6 "math" 7 ) 8 9 // MaxInt is the maximum platform dependent signed integer. 10 const MaxInt = int(^uint(0) >> 1) 11 12 // Mode is a mapping mode. 13 type Mode int 14 15 const ( 16 // Share this mapping and allow the read-only access 17 ModeReadOnly Mode = iota 18 19 // Share this mapping 20 // Updates to the mapping are visible to other processes 21 // mapping the same region, and are carried through to the underlying file. 22 // To precisely control when updates are carried through to the underlying file 23 // requires the use of Mapping.Sync. 24 ModeReadWrite 25 26 // Create a private copy-on-write mapping. 27 // Updates to the mapping are not visible to other processes 28 // mapping the same region, and are not carried through to the underlying file. 29 // It is unspecified whether changes made to the file are visible in the mapped region 30 ModeWriteCopy 31 ) 32 33 // Flag is a mapping flag 34 type Flag int 35 36 const ( 37 // Mapped memory pages may be executed 38 FlagExecutable Flag = 1 << iota 39 ) 40 41 // Mapping contains the cross-platform parts of a mapping. 42 type mapping struct { 43 // writable specifies whether the mapped memory pages may be written. 44 writable bool 45 // executable specifies whether the mapped memory pages may be executed. 46 executable bool 47 // address specifies the pointer to the mapped memory. 48 address uintptr 49 // memory specifies the byte slice which wraps the mapped memory. 50 memory []byte 51 // off is the current offset 52 off int64 53 // segment specifies the lazily initialized data segment on top of the mapped memory. 54 segment *segment.Segment 55 } 56 57 // Writable returns true if the mapped memory pages may be written. 58 func (m *mapping) Writable() bool { 59 return m.writable 60 } 61 62 // Executable returns true if the mapped memory pages may be executed. 63 func (m *mapping) Executable() bool { 64 return m.executable 65 } 66 67 // Address returns the pointer to the mapped memory. 68 func (m *mapping) Address() uintptr { 69 return m.address 70 } 71 72 // Length returns the mapped memory length in bytes. 73 func (m *mapping) Length() uintptr { 74 return uintptr(len(m.memory)) 75 } 76 77 // Memory returns the byte slice which wraps the mapped memory. 78 func (m *mapping) Memory() []byte { 79 return m.memory 80 } 81 82 // Segment returns the data segment on top of the mapped memory. 83 func (m *mapping) Segment() *segment.Segment { 84 if m.segment == nil { 85 m.segment = segment.New(0, m.memory) 86 } 87 return m.segment 88 } 89 90 // access checks given offset and length to match the available bounds 91 // and returns ErrOutOfBounds error at the access violation. 92 func (m *mapping) access(offset int64, length int) error { 93 if offset < 0 || offset > math.MaxInt64-int64(length) || offset+int64(length) > int64(len(m.memory)) { 94 return ErrOutOfBounds 95 } 96 return nil 97 } 98 99 // Read reads len(buf) bytes from the internal offset from the mapped memory. 100 // If the offset is out of the available bounds or there are not enough bytes to read 101 // the ErrOutOfBounds error will be returned. Otherwise len(buf) will be returned 102 // with no errors. Read implements the io.Reader interface. 103 func (m *mapping) Read(buf []byte) (int, error) { 104 if m.memory == nil { 105 return 0, ErrClosed 106 } 107 if err := m.access(m.off, len(buf)); err != nil { 108 return 0, err 109 } 110 n := copy(buf, m.memory[m.off:]) 111 m.off += int64(n) 112 return n, nil 113 } 114 115 // ReadAt reads len(buf) bytes at the given offset from start of the mapped memory from the mapped memory. 116 // If the given offset is out of the available bounds or there are not enough bytes to read 117 // the ErrOutOfBounds error will be returned. Otherwise len(buf) will be returned with no errors. 118 // ReadAt implements the io.ReaderAt interface. 119 func (m *mapping) ReadAt(buf []byte, offset int64) (int, error) { 120 if m.memory == nil { 121 return 0, ErrClosed 122 } 123 if err := m.access(offset, len(buf)); err != nil { 124 return 0, err 125 } 126 return copy(buf, m.memory[offset:]), nil 127 } 128 129 // Write writes len(buf) bytes from the internal offset into the mapped memory. 130 // If the offset is out of the available bounds or there are not enough space to write all given bytes 131 // the ErrOutOfBounds error will be returned. Otherwise len(buf) will be returned with no errors. 132 // Write implements the io.Writer interface. 133 func (m *mapping) Write(buf []byte) (int, error) { 134 if m.memory == nil { 135 return 0, ErrClosed 136 } 137 if !m.writable { 138 return 0, ErrReadOnly 139 } 140 if err := m.access(m.off, len(buf)); err != nil { 141 return 0, err 142 } 143 n := copy(m.memory[m.off:], buf) 144 m.off += int64(n) 145 return n, nil 146 } 147 148 // WriteAt writes len(buf) bytes at the given offset from start of the mapped memory into the mapped memory. 149 // If the given offset is out of the available bounds or there are not enough space to write all given bytes 150 // the ErrOutOfBounds error will be returned. Otherwise len(buf) will be returned with no errors. 151 // WriteAt implements the io.WriterAt interface. 152 func (m *mapping) WriteAt(buf []byte, offset int64) (int, error) { 153 if m.memory == nil { 154 return 0, ErrClosed 155 } 156 if !m.writable { 157 return 0, ErrReadOnly 158 } 159 if err := m.access(offset, len(buf)); err != nil { 160 return 0, err 161 } 162 return copy(m.memory[offset:], buf), nil 163 } 164 165 // Seek sets the offset for the next Read or Write to offset, interpreted according to whence: SeekStart means 166 // relative to the start of the file, SeekCurrent means relative to the current offset, and SeekEnd means relative 167 // to the end. Seek returns the new offset relative to the start of the file and an error, if any. 168 // Seeking to an offset before the start of the file is an error. Seeking to any positive offset is legal, but the 169 // behavior of subsequent I/O operations on the underlying object is implementation-dependent. 170 func (m *mapping) Seek(offset int64, whence int) (int64, error) { 171 if m.memory == nil { 172 return 0, ErrClosed 173 } 174 if err := m.access(offset, 0); err != nil { 175 return 0, err 176 } 177 switch whence { 178 default: 179 return 0, ErrSeekWhence 180 case io.SeekStart: 181 offset += 0 182 case io.SeekCurrent: 183 offset += m.off 184 case io.SeekEnd: 185 offset += int64(len(m.memory)) 186 } 187 if offset < 0 { 188 return 0, ErrSeekOffset 189 } 190 m.off = offset 191 return offset - 0, nil 192 }