github.com/flower-corp/rosedb@v1.1.2-0.20230117132829-21dc4f7b319a/ioselector/mmap.go (about) 1 package ioselector 2 3 import ( 4 "github.com/flower-corp/rosedb/mmap" 5 "io" 6 "os" 7 ) 8 9 // MMapSelector represents using memory-mapped file I/O. 10 type MMapSelector struct { 11 fd *os.File 12 buf []byte // a buffer of mmap 13 bufLen int64 14 } 15 16 // NewMMapSelector create a new mmap selector. 17 func NewMMapSelector(fName string, fsize int64) (IOSelector, error) { 18 if fsize <= 0 { 19 return nil, ErrInvalidFsize 20 } 21 file, err := openFile(fName, fsize) 22 if err != nil { 23 return nil, err 24 } 25 buf, err := mmap.Mmap(file, true, fsize) 26 if err != nil { 27 return nil, err 28 } 29 30 return &MMapSelector{fd: file, buf: buf, bufLen: int64(len(buf))}, nil 31 } 32 33 // Write copy slice b into mapped region(buf) at offset. 34 func (lm *MMapSelector) Write(b []byte, offset int64) (int, error) { 35 length := int64(len(b)) 36 if length <= 0 { 37 return 0, nil 38 } 39 if offset < 0 || length+offset > lm.bufLen { 40 return 0, io.EOF 41 } 42 return copy(lm.buf[offset:], b), nil 43 } 44 45 // Read copy data from mapped region(buf) into slice b at offset. 46 func (lm *MMapSelector) Read(b []byte, offset int64) (int, error) { 47 if offset < 0 || offset >= lm.bufLen { 48 return 0, io.EOF 49 } 50 if offset+int64(len(b)) >= lm.bufLen { 51 return 0, io.EOF 52 } 53 return copy(b, lm.buf[offset:]), nil 54 } 55 56 // Sync synchronize the mapped buffer to the file's contents on disk. 57 func (lm *MMapSelector) Sync() error { 58 return mmap.Msync(lm.buf) 59 } 60 61 // Close sync/unmap mapped buffer and close fd. 62 func (lm *MMapSelector) Close() error { 63 if err := mmap.Msync(lm.buf); err != nil { 64 return err 65 } 66 if err := mmap.Munmap(lm.buf); err != nil { 67 return err 68 } 69 return lm.fd.Close() 70 } 71 72 // Delete delete mapped buffer and remove file on disk. 73 func (lm *MMapSelector) Delete() error { 74 if err := mmap.Munmap(lm.buf); err != nil { 75 return err 76 } 77 lm.buf = nil 78 79 if err := lm.fd.Truncate(0); err != nil { 80 return err 81 } 82 if err := lm.fd.Close(); err != nil { 83 return err 84 } 85 return os.Remove(lm.fd.Name()) 86 }