github.com/leslie-fei/fastcache@v0.0.0-20240520092641-b7a9eb05711f/mmap/mmap.go (about)

     1  package mmap
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"reflect"
     7  	"unsafe"
     8  
     9  	"github.com/edsrzf/mmap-go"
    10  )
    11  
    12  type Memory struct {
    13  	filepath string
    14  	bytes    uint64
    15  	file     *os.File
    16  	mmap     mmap.MMap
    17  	basep    unsafe.Pointer
    18  }
    19  
    20  func NewMemory(filepath string, bytes uint64) *Memory {
    21  	return &Memory{filepath: filepath, bytes: bytes}
    22  }
    23  
    24  func (m *Memory) Attach() (err error) {
    25  	if nil == m.file {
    26  		if m.file, err = os.OpenFile(m.filepath, os.O_RDWR|os.O_CREATE, 0666); nil != err {
    27  			return err
    28  		}
    29  
    30  		if err = m.file.Truncate(int64(m.bytes)); nil != err {
    31  			m.file.Close()
    32  			m.file = nil
    33  			return err
    34  		}
    35  
    36  		if m.mmap, err = mmap.Map(m.file, mmap.RDWR, 0); nil != err {
    37  			m.file.Close()
    38  			m.file = nil
    39  			return err
    40  		}
    41  
    42  		sh := (*reflect.SliceHeader)(unsafe.Pointer(&m.mmap))
    43  		m.basep = unsafe.Pointer(sh.Data)
    44  	}
    45  	return
    46  }
    47  
    48  func (m *Memory) Detach() error {
    49  	if nil != m.mmap {
    50  		if err := m.mmap.Unmap(); nil != err {
    51  			return err
    52  		}
    53  		m.mmap = nil
    54  		m.basep = unsafe.Pointer(nil)
    55  	}
    56  
    57  	if nil != m.file {
    58  		if err := m.file.Close(); nil != err {
    59  			return err
    60  		}
    61  		m.file = nil
    62  	}
    63  	return nil
    64  }
    65  
    66  func (m *Memory) Ptr() unsafe.Pointer {
    67  	return m.basep
    68  }
    69  
    70  func (m *Memory) Size() uint64 {
    71  	return m.bytes
    72  }
    73  
    74  func (m *Memory) PtrOffset(offset uint64) unsafe.Pointer {
    75  	if offset >= m.bytes {
    76  		panic(fmt.Errorf("offset overflow: %d > %d", offset, m.bytes))
    77  	}
    78  	return unsafe.Pointer(uintptr(m.basep) + uintptr(offset))
    79  }
    80  
    81  func (m *Memory) Travel(skipOffset uint64, fn func(ptr unsafe.Pointer, size uint64) uint64) {
    82  	for skipOffset < m.bytes {
    83  		if advanceBytes := fn(m.PtrOffset(skipOffset), m.bytes-skipOffset); advanceBytes > 0 {
    84  			skipOffset += advanceBytes
    85  			continue
    86  		}
    87  		break
    88  	}
    89  }