seaweedfs/weed/filesys/dirty_page.go

143 lines
3.4 KiB
Go
Raw Normal View History

package filesys
import (
"bytes"
2020-10-15 06:28:03 +00:00
"io"
2020-10-21 09:16:21 +00:00
"runtime"
2020-10-15 06:28:03 +00:00
"sync"
"time"
2020-10-21 09:16:21 +00:00
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
)
var (
concurrentWriterLimit = runtime.NumCPU()
)
type ContinuousDirtyPages struct {
2020-10-16 19:54:23 +00:00
intervals *ContinuousIntervals
f *File
writeWaitGroup sync.WaitGroup
chunkSaveErrChan chan error
chunkSaveErrChanClosed bool
2020-10-21 09:16:21 +00:00
lastErr error
2020-10-16 19:54:23 +00:00
lock sync.Mutex
collection string
replication string
}
2018-05-29 08:21:21 +00:00
func newDirtyPages(file *File) *ContinuousDirtyPages {
2020-10-21 09:16:21 +00:00
dirtyPages := &ContinuousDirtyPages{
2020-10-15 06:28:03 +00:00
intervals: &ContinuousIntervals{},
f: file,
2020-10-21 09:16:21 +00:00
chunkSaveErrChan: make(chan error, concurrentWriterLimit),
}
2020-10-21 09:16:21 +00:00
go func() {
for t := range dirtyPages.chunkSaveErrChan {
if t != nil {
dirtyPages.lastErr = t
}
}
}()
return dirtyPages
2018-05-29 08:21:21 +00:00
}
2020-10-15 06:28:03 +00:00
func (pages *ContinuousDirtyPages) AddPage(offset int64, data []byte) {
2020-08-31 03:12:04 +00:00
glog.V(4).Infof("%s AddPage [%d,%d) of %d bytes", pages.f.fullpath(), offset, offset+int64(len(data)), pages.f.entry.Attributes.FileSize)
2019-01-01 10:14:40 +00:00
if len(data) > int(pages.f.wfs.option.ChunkSizeLimit) {
2018-05-31 05:09:24 +00:00
// this is more than what buffer can hold.
2020-10-15 06:28:03 +00:00
pages.flushAndSave(offset, data)
}
2020-01-26 21:01:11 +00:00
pages.intervals.AddInterval(data, offset)
if pages.intervals.TotalSize() > pages.f.wfs.option.ChunkSizeLimit {
2020-10-15 06:28:03 +00:00
pages.saveExistingLargestPageToStorage()
}
return
}
2020-10-15 06:28:03 +00:00
func (pages *ContinuousDirtyPages) flushAndSave(offset int64, data []byte) {
// flush existing
2020-10-15 06:28:03 +00:00
pages.saveExistingPagesToStorage()
// flush the new page
2020-10-15 06:28:03 +00:00
pages.saveToStorage(bytes.NewReader(data), offset, int64(len(data)))
return
}
2020-10-15 06:28:03 +00:00
func (pages *ContinuousDirtyPages) saveExistingPagesToStorage() {
for pages.saveExistingLargestPageToStorage() {
}
}
2020-10-15 06:28:03 +00:00
func (pages *ContinuousDirtyPages) saveExistingLargestPageToStorage() (hasSavedData bool) {
maxList := pages.intervals.RemoveLargestIntervalLinkedList()
if maxList == nil {
2020-10-15 06:28:03 +00:00
return false
}
fileSize := int64(pages.f.entry.Attributes.FileSize)
2020-10-15 06:28:03 +00:00
chunkSize := min(maxList.Size(), fileSize-maxList.Offset())
if chunkSize == 0 {
return false
}
2020-10-15 06:28:03 +00:00
pages.saveToStorage(maxList.ToReader(), maxList.Offset(), chunkSize)
return true
}
2020-10-15 06:28:03 +00:00
func (pages *ContinuousDirtyPages) saveToStorage(reader io.Reader, offset int64, size int64) {
2020-10-16 19:54:23 +00:00
if pages.chunkSaveErrChanClosed {
2020-10-21 09:42:23 +00:00
pages.chunkSaveErrChan = make(chan error, concurrentWriterLimit)
2020-10-16 19:54:23 +00:00
pages.chunkSaveErrChanClosed = false
}
mtime := time.Now().UnixNano()
2020-10-15 06:28:03 +00:00
pages.writeWaitGroup.Add(1)
go func() {
defer pages.writeWaitGroup.Done()
2020-10-15 06:28:03 +00:00
dir, _ := pages.f.fullpath().DirAndName()
2020-10-15 06:28:03 +00:00
reader = io.LimitReader(reader, size)
chunk, collection, replication, err := pages.f.wfs.saveDataAsChunk(dir)(reader, pages.f.Name, offset)
if err != nil {
glog.V(0).Infof("%s saveToStorage [%d,%d): %v", pages.f.fullpath(), offset, offset+size, err)
pages.chunkSaveErrChan <- err
return
}
chunk.Mtime = mtime
2020-10-15 06:28:03 +00:00
pages.collection, pages.replication = collection, replication
pages.f.addChunks([]*filer_pb.FileChunk{chunk})
2020-10-21 09:17:40 +00:00
glog.V(3).Infof("%s saveToStorage [%d,%d)", pages.f.fullpath(), offset, offset+size)
2020-10-15 06:28:03 +00:00
}()
}
2018-05-29 08:21:21 +00:00
func max(x, y int64) int64 {
if x > y {
return x
}
return y
}
func min(x, y int64) int64 {
if x < y {
return x
}
return y
}
2020-08-17 18:12:10 +00:00
func (pages *ContinuousDirtyPages) ReadDirtyDataAt(data []byte, startOffset int64) (maxStop int64) {
return pages.intervals.ReadDataAt(data, startOffset)
}