diff --git a/mmap.go b/mmap.go index 936d316..a81caa6 100644 --- a/mmap.go +++ b/mmap.go @@ -2,9 +2,7 @@ package mmap import ( "errors" - "io" "os" - "strings" "syscall" ) @@ -15,25 +13,8 @@ var ( ErrIndexOutOfBound = errors.New("offset out of mapped region") ) -// File provides an interface to a memory mapped file -type File interface { - io.ReaderAt - io.WriterAt - - ReadStringAt(dest *strings.Builder, offset int64) int - WriteStringAt(src string, offset int64) int - ReadUint64At(offset int64) uint64 - WriteUint64At(num uint64, offset int64) - - Lock() error - Unlock() error - Advise(advice int) error - Flush(flags int) error - Unmap() error -} - -// FileImpl provides abstraction around a memory mapped file -type FileImpl struct { +// File provides abstraction around a memory mapped file +type File struct { data []byte length int64 } @@ -45,13 +26,13 @@ type FileImpl struct { // then all the mapped memory is accessible // case 2 => if file size <= memory region (offset + length) // then from offset to file size memory region is accessible -func NewSharedFileMmap(f *os.File, offset int64, length int, prot int) (File, error) { +func NewSharedFileMmap(f *os.File, offset int64, length int, prot int) (*File, error) { data, err := syscall.Mmap(int(f.Fd()), offset, length, prot, syscall.MAP_SHARED) if err != nil { return nil, err } - return &FileImpl{ + return &File{ data: data, length: int64(length), }, nil @@ -59,7 +40,7 @@ func NewSharedFileMmap(f *os.File, offset int64, length int, prot int) (File, er // Unmap unmaps the memory mapped file. An error will be returned // if any of the functions are called on Mmap after calling Unmap -func (m *FileImpl) Unmap() error { +func (m *File) Unmap() error { err := syscall.Munmap(m.data) m.data = nil return err diff --git a/mmap_data.go b/mmap_data.go index 636eed1..9c95359 100644 --- a/mmap_data.go +++ b/mmap_data.go @@ -7,7 +7,7 @@ import ( "unsafe" ) -func (m *FileImpl) boundaryChecks(offset, numBytes int64) { +func (m *File) boundaryChecks(offset, numBytes int64) { if m.data == nil { panic(ErrUnmappedMemory) } else if offset+numBytes > m.length || offset < 0 { @@ -23,7 +23,7 @@ func (m *FileImpl) boundaryChecks(offset, numBytes int64) { // Case 2: len(dest) < (m.length - offset) // => copies len(dest) bytes to dest from mapped region // err is always nil, hence, can be ignored -func (m *FileImpl) ReadAt(dest []byte, offset int64) (int, error) { +func (m *File) ReadAt(dest []byte, offset int64) (int, error) { m.boundaryChecks(offset, 1) return copy(dest, m.data[offset:]), nil } @@ -36,7 +36,7 @@ func (m *FileImpl) ReadAt(dest []byte, offset int64) (int, error) { // Case 2: len(src) < (m.length - offset) // => copies len(src) bytes to the mapped region from src // err is always nil, hence, can be ignored -func (m *FileImpl) WriteAt(src []byte, offset int64) (int, error) { +func (m *File) WriteAt(src []byte, offset int64) (int, error) { m.boundaryChecks(offset, 1) return copy(m.data[offset:], src), nil } @@ -44,7 +44,7 @@ func (m *FileImpl) WriteAt(src []byte, offset int64) (int, error) { // ReadStringAt copies data to dest string builder from mapped region starting at // given offset until the min value of (length - offset) or (dest.Cap() - dest.Len()) // and returns number of bytes copied to the dest slice. -func (m *FileImpl) ReadStringAt(dest *strings.Builder, offset int64) int { +func (m *File) ReadStringAt(dest *strings.Builder, offset int64) int { m.boundaryChecks(offset, 1) dataLength := m.length - offset @@ -60,25 +60,25 @@ func (m *FileImpl) ReadStringAt(dest *strings.Builder, offset int64) int { // WriteStringAt copies data to mapped region from the src string starting at // given offset and returns number of bytes copied to the mapped region. -func (m *FileImpl) WriteStringAt(src string, offset int64) int { +func (m *File) WriteStringAt(src string, offset int64) int { m.boundaryChecks(offset, 1) return copy(m.data[offset:], src) } // ReadUint64At reads uint64 from offset -func (m *FileImpl) ReadUint64At(offset int64) uint64 { +func (m *File) ReadUint64At(offset int64) uint64 { m.boundaryChecks(offset, 8) return binary.LittleEndian.Uint64(m.data[offset : offset+8]) } // WriteUint64At writes num at offset -func (m *FileImpl) WriteUint64At(num uint64, offset int64) { +func (m *File) WriteUint64At(num uint64, offset int64) { m.boundaryChecks(offset, 8) binary.LittleEndian.PutUint64(m.data[offset:offset+8], num) } // Flush flushes the memory mapped region to disk -func (m *FileImpl) Flush(flags int) error { +func (m *File) Flush(flags int) error { _, _, err := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(&m.data[0])), uintptr(m.length), uintptr(flags)) if err != 0 { diff --git a/mmap_page.go b/mmap_page.go index a22af8d..edd1cdf 100644 --- a/mmap_page.go +++ b/mmap_page.go @@ -6,7 +6,7 @@ import ( ) // Advise provides hints to kernel regarding the use of memory mapped region -func (m *FileImpl) Advise(advice int) error { +func (m *File) Advise(advice int) error { _, _, err := syscall.Syscall(syscall.SYS_MADVISE, uintptr(unsafe.Pointer(&m.data[0])), uintptr(m.length), uintptr(advice)) if err != 0 { @@ -17,7 +17,7 @@ func (m *FileImpl) Advise(advice int) error { } // Lock locks all the mapped memory to RAM, preventing the pages from swapping out -func (m *FileImpl) Lock() error { +func (m *File) Lock() error { _, _, err := syscall.Syscall(syscall.SYS_MLOCK, uintptr(unsafe.Pointer(&m.data[0])), uintptr(m.length), 0) if err != 0 { @@ -28,7 +28,7 @@ func (m *FileImpl) Lock() error { } // Unlock unlocks the mapped memory from RAM, enabling swapping out of RAM if required -func (m *FileImpl) Unlock() error { +func (m *File) Unlock() error { _, _, err := syscall.Syscall(syscall.SYS_MUNLOCK, uintptr(unsafe.Pointer(&m.data[0])), uintptr(m.length), 0) if err != 0 {