1
0
Fork 0
mirror of https://github.com/chrislusf/seaweedfs synced 2024-07-03 07:36:45 +02:00

refactor memory mapped file into backend storage

This commit is contained in:
Chris Lu 2019-11-09 00:10:59 -08:00
parent c5c1d83d91
commit 85f8649320
10 changed files with 124 additions and 122 deletions

View file

@ -21,8 +21,6 @@ type MemoryMap struct {
End_of_file int64 End_of_file int64
} }
var FileMemoryMap = make(map[string]*MemoryMap)
func ReadMemoryMapMaxSizeMb(memoryMapMaxSizeMbString string) (uint32, error) { func ReadMemoryMapMaxSizeMb(memoryMapMaxSizeMbString string) (uint32, error) {
if memoryMapMaxSizeMbString == "" { if memoryMapMaxSizeMbString == "" {
return 0, nil return 0, nil

View file

@ -0,0 +1,60 @@
package memory_map
import (
"os"
"time"
"github.com/chrislusf/seaweedfs/weed/storage/backend"
)
var (
_ backend.DataStorageBackend = &MemoryMappedFile{}
)
type MemoryMappedFile struct {
mm *MemoryMap
}
func NewMemoryMappedFile(f *os.File, memoryMapSizeMB uint32) *MemoryMappedFile {
mmf := &MemoryMappedFile{
mm : new(MemoryMap),
}
mmf.mm.CreateMemoryMap(f, 1024*1024*uint64(memoryMapSizeMB))
return mmf
}
func (mmf *MemoryMappedFile) ReadAt(p []byte, off int64) (n int, err error) {
readBytes, e := mmf.mm.ReadMemory(uint64(off), uint64(len(p)))
if e != nil {
return 0, e
}
// TODO avoid the extra copy
copy(p, readBytes)
return len(readBytes), nil
}
func (mmf *MemoryMappedFile) WriteAt(p []byte, off int64) (n int, err error) {
mmf.mm.WriteMemory(uint64(off), uint64(len(p)), p)
return len(p), nil
}
func (mmf *MemoryMappedFile) Truncate(off int64) error {
return nil
}
func (mmf *MemoryMappedFile) Close() error {
mmf.mm.DeleteFileAndMemoryMap()
return nil
}
func (mmf *MemoryMappedFile) GetStat() (datSize int64, modTime time.Time, err error) {
stat, e := mmf.mm.File.Stat()
if e == nil {
return stat.Size(), stat.ModTime(), nil
}
return 0, time.Time{}, err
}
func (mmf *MemoryMappedFile) String() string {
return mmf.mm.File.Name()
}

View file

@ -8,7 +8,6 @@ import (
"github.com/chrislusf/seaweedfs/weed/glog" "github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/storage/backend" "github.com/chrislusf/seaweedfs/weed/storage/backend"
"github.com/chrislusf/seaweedfs/weed/storage/backend/memory_map"
. "github.com/chrislusf/seaweedfs/weed/storage/types" . "github.com/chrislusf/seaweedfs/weed/storage/types"
"github.com/chrislusf/seaweedfs/weed/util" "github.com/chrislusf/seaweedfs/weed/util"
) )
@ -128,8 +127,6 @@ func (n *Needle) prepareWriteBuffer(version Version) ([]byte, uint32, int64, err
func (n *Needle) Append(w backend.DataStorageBackend, version Version) (offset uint64, size uint32, actualSize int64, err error) { func (n *Needle) Append(w backend.DataStorageBackend, version Version) (offset uint64, size uint32, actualSize int64, err error) {
mMap, exists := memory_map.FileMemoryMap[w.String()]
if !exists {
if end, _, e := w.GetStat(); e == nil { if end, _, e := w.GetStat(); e == nil {
defer func(w backend.DataStorageBackend, off int64) { defer func(w backend.DataStorageBackend, off int64) {
if err != nil { if err != nil {
@ -143,19 +140,12 @@ func (n *Needle) Append(w backend.DataStorageBackend, version Version) (offset u
err = fmt.Errorf("Cannot Read Current Volume Position: %v", e) err = fmt.Errorf("Cannot Read Current Volume Position: %v", e)
return return
} }
} else {
offset = uint64(mMap.End_of_file + 1)
}
bytesToWrite, size, actualSize, err := n.prepareWriteBuffer(version) bytesToWrite, size, actualSize, err := n.prepareWriteBuffer(version)
if err == nil { if err == nil {
if exists {
mMap.WriteMemory(offset, uint64(len(bytesToWrite)), bytesToWrite)
} else {
_, err = w.WriteAt(bytesToWrite, int64(offset)) _, err = w.WriteAt(bytesToWrite, int64(offset))
} }
}
return offset, size, actualSize, err return offset, size, actualSize, err
} }
@ -165,14 +155,9 @@ func ReadNeedleBlob(r backend.DataStorageBackend, offset int64, size uint32, ver
dataSize := GetActualSize(size, version) dataSize := GetActualSize(size, version)
dataSlice = make([]byte, int(dataSize)) dataSlice = make([]byte, int(dataSize))
mMap, exists := memory_map.FileMemoryMap[r.String()]
if exists {
dataSlice, err := mMap.ReadMemory(uint64(offset), uint64(dataSize))
return dataSlice, err
} else {
_, err = r.ReadAt(dataSlice, offset) _, err = r.ReadAt(dataSlice, offset)
return dataSlice, err return dataSlice, err
}
} }
// ReadBytes hydrates the needle from the bytes buffer, with only n.Id is set. // ReadBytes hydrates the needle from the bytes buffer, with only n.Id is set.
@ -286,19 +271,12 @@ func ReadNeedleHeader(r backend.DataStorageBackend, version Version, offset int6
if version == Version1 || version == Version2 || version == Version3 { if version == Version1 || version == Version2 || version == Version3 {
bytes = make([]byte, NeedleHeaderSize) bytes = make([]byte, NeedleHeaderSize)
mMap, exists := memory_map.FileMemoryMap[r.String()]
if exists {
bytes, err = mMap.ReadMemory(uint64(offset), NeedleHeaderSize)
if err != nil {
return nil, bytes, 0, err
}
} else {
var count int var count int
count, err = r.ReadAt(bytes, offset) count, err = r.ReadAt(bytes, offset)
if count <= 0 || err != nil { if count <= 0 || err != nil {
return nil, bytes, 0, err return nil, bytes, 0, err
} }
}
n.ParseNeedleHeader(bytes) n.ParseNeedleHeader(bytes)
bodyLength = NeedleBodyLength(n.Size, version) bodyLength = NeedleBodyLength(n.Size, version)
} }

View file

@ -6,12 +6,13 @@ import (
"os" "os"
"github.com/chrislusf/seaweedfs/weed/glog" "github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/storage/backend"
) )
func createVolumeFile(fileName string, preallocate int64, memoryMapSizeMB uint32) (*os.File, error) { func createVolumeFile(fileName string, preallocate int64, memoryMapSizeMB uint32) (backend.DataStorageBackend, error) {
file, e := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) file, e := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if preallocate > 0 { if preallocate > 0 {
glog.V(0).Infof("Preallocated disk space for %s is not supported", fileName) glog.V(0).Infof("Preallocated disk space for %s is not supported", fileName)
} }
return file, e return backend.NewDiskFile(file), e
} }

View file

@ -7,13 +7,14 @@ import (
"syscall" "syscall"
"github.com/chrislusf/seaweedfs/weed/glog" "github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/storage/backend"
) )
func createVolumeFile(fileName string, preallocate int64, memoryMapSizeMB uint32) (*os.File, error) { func createVolumeFile(fileName string, preallocate int64, memoryMapSizeMB uint32) (backend.DataStorageBackend, error) {
file, e := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) file, e := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if preallocate != 0 { if preallocate != 0 {
syscall.Fallocate(int(file.Fd()), 1, 0, preallocate) syscall.Fallocate(int(file.Fd()), 1, 0, preallocate)
glog.V(0).Infof("Preallocated %d bytes disk space for %s", preallocate, fileName) glog.V(0).Infof("Preallocated %d bytes disk space for %s", preallocate, fileName)
} }
return file, e return backend.NewDiskFile(file), e
} }

View file

@ -3,19 +3,15 @@
package storage package storage
import ( import (
"os"
"github.com/chrislusf/seaweedfs/weed/storage/backend/memory_map" "github.com/chrislusf/seaweedfs/weed/storage/backend/memory_map"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"github.com/chrislusf/seaweedfs/weed/glog" "github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/storage/backend"
"github.com/chrislusf/seaweedfs/weed/storage/backend/memory_map/os_overloads" "github.com/chrislusf/seaweedfs/weed/storage/backend/memory_map/os_overloads"
) )
func createVolumeFile(fileName string, preallocate int64, memoryMapSizeMB uint32) (*os.File, error) { func createVolumeFile(fileName string, preallocate int64, memoryMapSizeMB uint32) (backend.DataStorageBackend, error) {
mMap, exists := memory_map.FileMemoryMap[fileName]
if !exists {
if preallocate > 0 { if preallocate > 0 {
glog.V(0).Infof("Preallocated disk space for %s is not supported", fileName) glog.V(0).Infof("Preallocated disk space for %s is not supported", fileName)
@ -23,16 +19,10 @@ func createVolumeFile(fileName string, preallocate int64, memoryMapSizeMB uint32
if memoryMapSizeMB > 0 { if memoryMapSizeMB > 0 {
file, e := os_overloads.OpenFile(fileName, windows.O_RDWR|windows.O_CREAT, 0644, true) file, e := os_overloads.OpenFile(fileName, windows.O_RDWR|windows.O_CREAT, 0644, true)
memory_map.FileMemoryMap[fileName] = new(memory_map.MemoryMap) return memory_map.NewMemoryMappedFile(file, memoryMapSizeMB), e
new_mMap := memory_map.FileMemoryMap[fileName]
new_mMap.CreateMemoryMap(file, 1024*1024*uint64(memoryMapSizeMB))
return file, e
} else { } else {
file, e := os_overloads.OpenFile(fileName, windows.O_RDWR|windows.O_CREAT|windows.O_TRUNC, 0644, false) file, e := os_overloads.OpenFile(fileName, windows.O_RDWR|windows.O_CREAT|windows.O_TRUNC, 0644, false)
return file, e return backend.NewDiskFile(file), e
}
} else {
return mMap.File, nil
} }
} }

View file

@ -25,13 +25,13 @@ func (v *Volume) load(alsoLoadIndex bool, createDatIfMissing bool, needleMapKind
var e error var e error
fileName := v.FileName() fileName := v.FileName()
alreadyHasSuperBlock := false alreadyHasSuperBlock := false
var dataFile *os.File
// open dat file // open dat file
if exists, canRead, canWrite, modifiedTime, fileSize := checkFile(fileName + ".dat"); exists { if exists, canRead, canWrite, modifiedTime, fileSize := checkFile(fileName + ".dat"); exists {
if !canRead { if !canRead {
return fmt.Errorf("cannot read Volume Data file %s.dat", fileName) return fmt.Errorf("cannot read Volume Data file %s.dat", fileName)
} }
var dataFile *os.File
if canWrite { if canWrite {
dataFile, e = os.OpenFile(fileName+".dat", os.O_RDWR|os.O_CREATE, 0644) dataFile, e = os.OpenFile(fileName+".dat", os.O_RDWR|os.O_CREATE, 0644)
} else { } else {
@ -43,14 +43,14 @@ func (v *Volume) load(alsoLoadIndex bool, createDatIfMissing bool, needleMapKind
if fileSize >= _SuperBlockSize { if fileSize >= _SuperBlockSize {
alreadyHasSuperBlock = true alreadyHasSuperBlock = true
} }
v.DataBackend = backend.NewDiskFile(dataFile)
} else { } else {
if createDatIfMissing { if createDatIfMissing {
dataFile, e = createVolumeFile(fileName+".dat", preallocate, v.MemoryMapMaxSizeMb) v.DataBackend, e = createVolumeFile(fileName+".dat", preallocate, v.MemoryMapMaxSizeMb)
} else { } else {
return fmt.Errorf("Volume Data file %s.dat does not exist.", fileName) return fmt.Errorf("Volume Data file %s.dat does not exist.", fileName)
} }
} }
v.DataBackend = backend.NewDiskFile(dataFile)
if e != nil { if e != nil {
if !os.IsPermission(e) { if !os.IsPermission(e) {

View file

@ -10,7 +10,6 @@ import (
"github.com/chrislusf/seaweedfs/weed/glog" "github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/storage/backend" "github.com/chrislusf/seaweedfs/weed/storage/backend"
"github.com/chrislusf/seaweedfs/weed/storage/backend/memory_map"
"github.com/chrislusf/seaweedfs/weed/storage/needle" "github.com/chrislusf/seaweedfs/weed/storage/needle"
. "github.com/chrislusf/seaweedfs/weed/storage/types" . "github.com/chrislusf/seaweedfs/weed/storage/types"
) )
@ -46,12 +45,6 @@ func (v *Volume) Destroy() (err error) {
err = fmt.Errorf("volume %d is compacting", v.Id) err = fmt.Errorf("volume %d is compacting", v.Id)
return return
} }
mMap, exists := memory_map.FileMemoryMap[v.DataBackend.String()]
if exists {
mMap.DeleteFileAndMemoryMap()
delete(memory_map.FileMemoryMap, v.DataBackend.String())
}
v.Close() v.Close()
os.Remove(v.FileName() + ".dat") os.Remove(v.FileName() + ".dat")
os.Remove(v.FileName() + ".idx") os.Remove(v.FileName() + ".idx")

View file

@ -4,11 +4,9 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/chrislusf/seaweedfs/weed/storage/backend"
"github.com/chrislusf/seaweedfs/weed/storage/backend/memory_map"
"github.com/chrislusf/seaweedfs/weed/glog" "github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/pb/master_pb" "github.com/chrislusf/seaweedfs/weed/pb/master_pb"
"github.com/chrislusf/seaweedfs/weed/storage/backend"
"github.com/chrislusf/seaweedfs/weed/storage/needle" "github.com/chrislusf/seaweedfs/weed/storage/needle"
"github.com/chrislusf/seaweedfs/weed/util" "github.com/chrislusf/seaweedfs/weed/util"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
@ -78,14 +76,6 @@ func (s *SuperBlock) Initialized() bool {
func (v *Volume) maybeWriteSuperBlock() error { func (v *Volume) maybeWriteSuperBlock() error {
mMap, exists := memory_map.FileMemoryMap[v.DataBackend.String()]
if exists {
if mMap.End_of_file == -1 {
v.SuperBlock.version = needle.CurrentVersion
mMap.WriteMemory(0, uint64(len(v.SuperBlock.Bytes())), v.SuperBlock.Bytes())
}
return nil
} else {
datSize, _, e := v.DataBackend.GetStat() datSize, _, e := v.DataBackend.GetStat()
if e != nil { if e != nil {
glog.V(0).Infof("failed to stat datafile %s: %v", v.DataBackend.String(), e) glog.V(0).Infof("failed to stat datafile %s: %v", v.DataBackend.String(), e)
@ -106,7 +96,6 @@ func (v *Volume) maybeWriteSuperBlock() error {
} }
} }
return e return e
}
} }
func (v *Volume) readSuperBlock() (err error) { func (v *Volume) readSuperBlock() (err error) {
@ -118,19 +107,10 @@ func (v *Volume) readSuperBlock() (err error) {
func ReadSuperBlock(datBackend backend.DataStorageBackend) (superBlock SuperBlock, err error) { func ReadSuperBlock(datBackend backend.DataStorageBackend) (superBlock SuperBlock, err error) {
header := make([]byte, _SuperBlockSize) header := make([]byte, _SuperBlockSize)
mMap, exists := memory_map.FileMemoryMap[datBackend.String()]
if exists {
header, err = mMap.ReadMemory(0, _SuperBlockSize)
if err != nil {
err = fmt.Errorf("cannot read volume %s super block: %v", datBackend.String(), err)
return
}
} else {
if _, e := datBackend.ReadAt(header, 0); e != nil { if _, e := datBackend.ReadAt(header, 0); e != nil {
err = fmt.Errorf("cannot read volume %s super block: %v", datBackend.String(), e) err = fmt.Errorf("cannot read volume %s super block: %v", datBackend.String(), e)
return return
} }
}
superBlock.version = needle.Version(header[0]) superBlock.version = needle.Version(header[0])
if superBlock.ReplicaPlacement, err = NewReplicaPlacementFromByte(header[1]); err != nil { if superBlock.ReplicaPlacement, err = NewReplicaPlacementFromByte(header[1]); err != nil {

View file

@ -312,7 +312,8 @@ func (scanner *VolumeFileScanner4Vacuum) VisitNeedle(n *needle.Needle, offset in
func (v *Volume) copyDataAndGenerateIndexFile(dstName, idxName string, preallocate int64, compactionBytePerSecond int64) (err error) { func (v *Volume) copyDataAndGenerateIndexFile(dstName, idxName string, preallocate int64, compactionBytePerSecond int64) (err error) {
var ( var (
dst, idx *os.File dst backend.DataStorageBackend
idx *os.File
) )
if dst, err = createVolumeFile(dstName, preallocate, 0); err != nil { if dst, err = createVolumeFile(dstName, preallocate, 0); err != nil {
return return
@ -328,7 +329,7 @@ func (v *Volume) copyDataAndGenerateIndexFile(dstName, idxName string, prealloca
v: v, v: v,
now: uint64(time.Now().Unix()), now: uint64(time.Now().Unix()),
nm: NewBtreeNeedleMap(idx), nm: NewBtreeNeedleMap(idx),
dstBackend: backend.NewDiskFile(dst), dstBackend: dst,
writeThrottler: util.NewWriteThrottler(compactionBytePerSecond), writeThrottler: util.NewWriteThrottler(compactionBytePerSecond),
} }
err = ScanVolumeFile(v.dir, v.Collection, v.Id, v.needleMapKind, scanner) err = ScanVolumeFile(v.dir, v.Collection, v.Id, v.needleMapKind, scanner)