You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							202 lines
						
					
					
						
							5.3 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							202 lines
						
					
					
						
							5.3 KiB
						
					
					
				| package page_writer | |
| 
 | |
| import ( | |
| 	"github.com/seaweedfs/seaweedfs/weed/glog" | |
| 	"github.com/seaweedfs/seaweedfs/weed/util" | |
| 	"github.com/seaweedfs/seaweedfs/weed/util/mem" | |
| 	"io" | |
| 	"os" | |
| 	"sync" | |
| ) | |
| 
 | |
| var ( | |
| 	_ = PageChunk(&SwapFileChunk{}) | |
| ) | |
| 
 | |
| type ActualChunkIndex int | |
| 
 | |
| type SwapFile struct { | |
| 	dir                 string | |
| 	file                *os.File | |
| 	chunkSize           int64 | |
| 	chunkTrackingLock   sync.Mutex | |
| 	activeChunkCount    int | |
| 	freeActualChunkList []ActualChunkIndex | |
| } | |
| 
 | |
| type SwapFileChunk struct { | |
| 	sync.RWMutex | |
| 	swapfile         *SwapFile | |
| 	usage            *ChunkWrittenIntervalList | |
| 	logicChunkIndex  LogicChunkIndex | |
| 	actualChunkIndex ActualChunkIndex | |
| 	activityScore    *ActivityScore | |
| 	//memChunk         *MemChunk | |
| } | |
| 
 | |
| func NewSwapFile(dir string, chunkSize int64) *SwapFile { | |
| 	return &SwapFile{ | |
| 		dir:       dir, | |
| 		file:      nil, | |
| 		chunkSize: chunkSize, | |
| 	} | |
| } | |
| func (sf *SwapFile) FreeResource() { | |
| 	if sf.file != nil { | |
| 		sf.file.Close() | |
| 		os.Remove(sf.file.Name()) | |
| 	} | |
| } | |
| 
 | |
| func (sf *SwapFile) NewSwapFileChunk(logicChunkIndex LogicChunkIndex) (tc *SwapFileChunk) { | |
| 	if sf.file == nil { | |
| 		var err error | |
| 		sf.file, err = os.CreateTemp(sf.dir, "") | |
| 		if err != nil { | |
| 			glog.Errorf("create swap file: %v", err) | |
| 			return nil | |
| 		} | |
| 	} | |
| 	sf.chunkTrackingLock.Lock() | |
| 	defer sf.chunkTrackingLock.Unlock() | |
| 
 | |
| 	sf.activeChunkCount++ | |
| 
 | |
| 	// assign a new physical chunk | |
| 	var actualChunkIndex ActualChunkIndex | |
| 	if len(sf.freeActualChunkList) > 0 { | |
| 		actualChunkIndex = sf.freeActualChunkList[0] | |
| 		sf.freeActualChunkList = sf.freeActualChunkList[1:] | |
| 	} else { | |
| 		actualChunkIndex = ActualChunkIndex(sf.activeChunkCount) | |
| 	} | |
| 
 | |
| 	swapFileChunk := &SwapFileChunk{ | |
| 		swapfile:         sf, | |
| 		usage:            newChunkWrittenIntervalList(), | |
| 		logicChunkIndex:  logicChunkIndex, | |
| 		actualChunkIndex: actualChunkIndex, | |
| 		activityScore:    NewActivityScore(), | |
| 		// memChunk:         NewMemChunk(logicChunkIndex, sf.chunkSize), | |
| 	} | |
| 
 | |
| 	// println(logicChunkIndex, "|", "++++", swapFileChunk.actualChunkIndex, swapFileChunk, sf) | |
| 	return swapFileChunk | |
| } | |
| 
 | |
| func (sc *SwapFileChunk) FreeResource() { | |
| 
 | |
| 	sc.Lock() | |
| 	defer sc.Unlock() | |
| 
 | |
| 	sc.swapfile.chunkTrackingLock.Lock() | |
| 	defer sc.swapfile.chunkTrackingLock.Unlock() | |
| 
 | |
| 	sc.swapfile.freeActualChunkList = append(sc.swapfile.freeActualChunkList, sc.actualChunkIndex) | |
| 	sc.swapfile.activeChunkCount-- | |
| 	// println(sc.logicChunkIndex, "|", "----", sc.actualChunkIndex, sc, sc.swapfile) | |
| } | |
| 
 | |
| func (sc *SwapFileChunk) WriteDataAt(src []byte, offset int64, tsNs int64) (n int) { | |
| 	sc.Lock() | |
| 	defer sc.Unlock() | |
| 
 | |
| 	// println(sc.logicChunkIndex, "|", tsNs, "write at", offset, len(src), sc.actualChunkIndex) | |
|  | |
| 	innerOffset := offset % sc.swapfile.chunkSize | |
| 	var err error | |
| 	n, err = sc.swapfile.file.WriteAt(src, int64(sc.actualChunkIndex)*sc.swapfile.chunkSize+innerOffset) | |
| 	sc.usage.MarkWritten(innerOffset, innerOffset+int64(n), tsNs) | |
| 	if err != nil { | |
| 		glog.Errorf("failed to write swap file %s: %v", sc.swapfile.file.Name(), err) | |
| 	} | |
| 	//sc.memChunk.WriteDataAt(src, offset, tsNs) | |
| 	sc.activityScore.MarkWrite() | |
| 
 | |
| 	return | |
| } | |
| 
 | |
| func (sc *SwapFileChunk) ReadDataAt(p []byte, off int64, tsNs int64) (maxStop int64) { | |
| 	sc.RLock() | |
| 	defer sc.RUnlock() | |
| 
 | |
| 	// println(sc.logicChunkIndex, "|", tsNs, "read at", off, len(p), sc.actualChunkIndex) | |
|  | |
| 	//memCopy := make([]byte, len(p)) | |
| 	//copy(memCopy, p) | |
|  | |
| 	chunkStartOffset := int64(sc.logicChunkIndex) * sc.swapfile.chunkSize | |
| 	for t := sc.usage.head.next; t != sc.usage.tail; t = t.next { | |
| 		logicStart := max(off, chunkStartOffset+t.StartOffset) | |
| 		logicStop := min(off+int64(len(p)), chunkStartOffset+t.stopOffset) | |
| 		if logicStart < logicStop { | |
| 			actualStart := logicStart - chunkStartOffset + int64(sc.actualChunkIndex)*sc.swapfile.chunkSize | |
| 			if n, err := sc.swapfile.file.ReadAt(p[logicStart-off:logicStop-off], actualStart); err != nil { | |
| 				if err == io.EOF && n == int(logicStop-logicStart) { | |
| 					err = nil | |
| 				} | |
| 				glog.Errorf("failed to reading swap file %s: %v", sc.swapfile.file.Name(), err) | |
| 				break | |
| 			} | |
| 			maxStop = max(maxStop, logicStop) | |
| 
 | |
| 			if t.TsNs > tsNs { | |
| 				println("read new data2", t.TsNs-tsNs, "ns") | |
| 			} | |
| 		} | |
| 	} | |
| 	//sc.memChunk.ReadDataAt(memCopy, off, tsNs) | |
| 	//if bytes.Compare(memCopy, p) != 0 { | |
| 	//	println("read wrong data from swap file", off, sc.logicChunkIndex) | |
| 	//} | |
|  | |
| 	sc.activityScore.MarkRead() | |
| 
 | |
| 	return | |
| } | |
| 
 | |
| func (sc *SwapFileChunk) IsComplete() bool { | |
| 	sc.RLock() | |
| 	defer sc.RUnlock() | |
| 	return sc.usage.IsComplete(sc.swapfile.chunkSize) | |
| } | |
| 
 | |
| func (sc *SwapFileChunk) ActivityScore() int64 { | |
| 	return sc.activityScore.ActivityScore() | |
| } | |
| 
 | |
| func (sc *SwapFileChunk) WrittenSize() int64 { | |
| 	sc.RLock() | |
| 	defer sc.RUnlock() | |
| 	return sc.usage.WrittenSize() | |
| } | |
| 
 | |
| func (sc *SwapFileChunk) SaveContent(saveFn SaveToStorageFunc) { | |
| 	sc.RLock() | |
| 	defer sc.RUnlock() | |
| 
 | |
| 	if saveFn == nil { | |
| 		return | |
| 	} | |
| 	// println(sc.logicChunkIndex, "|", "save") | |
| 	for t := sc.usage.head.next; t != sc.usage.tail; t = t.next { | |
| 		startOffset := t.StartOffset | |
| 		stopOffset := t.stopOffset | |
| 		tsNs := t.TsNs | |
| 		for t != sc.usage.tail && t.next.StartOffset == stopOffset { | |
| 			stopOffset = t.next.stopOffset | |
| 			t = t.next | |
| 			tsNs = max(tsNs, t.TsNs) | |
| 		} | |
| 
 | |
| 		data := mem.Allocate(int(stopOffset - startOffset)) | |
| 		n, _ := sc.swapfile.file.ReadAt(data, startOffset+int64(sc.actualChunkIndex)*sc.swapfile.chunkSize) | |
| 		if n > 0 { | |
| 			reader := util.NewBytesReader(data[:n]) | |
| 			saveFn(reader, int64(sc.logicChunkIndex)*sc.swapfile.chunkSize+startOffset, int64(n), tsNs, func() { | |
| 			}) | |
| 		} | |
| 		mem.Free(data) | |
| 	} | |
| 
 | |
| }
 |