page_chunk_swapfile.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. package page_writer
  2. import (
  3. "github.com/seaweedfs/seaweedfs/weed/glog"
  4. "github.com/seaweedfs/seaweedfs/weed/util"
  5. "github.com/seaweedfs/seaweedfs/weed/util/mem"
  6. "os"
  7. "sync"
  8. )
  9. var (
  10. _ = PageChunk(&SwapFileChunk{})
  11. )
  12. type ActualChunkIndex int
  13. type SwapFile struct {
  14. dir string
  15. file *os.File
  16. chunkSize int64
  17. chunkTrackingLock sync.Mutex
  18. activeChunkCount int
  19. freeActualChunkList []ActualChunkIndex
  20. }
  21. type SwapFileChunk struct {
  22. sync.RWMutex
  23. swapfile *SwapFile
  24. usage *ChunkWrittenIntervalList
  25. logicChunkIndex LogicChunkIndex
  26. actualChunkIndex ActualChunkIndex
  27. activityScore *ActivityScore
  28. //memChunk *MemChunk
  29. }
  30. func NewSwapFile(dir string, chunkSize int64) *SwapFile {
  31. return &SwapFile{
  32. dir: dir,
  33. file: nil,
  34. chunkSize: chunkSize,
  35. }
  36. }
  37. func (sf *SwapFile) FreeResource() {
  38. if sf.file != nil {
  39. sf.file.Close()
  40. os.Remove(sf.file.Name())
  41. }
  42. }
  43. func (sf *SwapFile) NewSwapFileChunk(logicChunkIndex LogicChunkIndex) (tc *SwapFileChunk) {
  44. if sf.file == nil {
  45. var err error
  46. sf.file, err = os.CreateTemp(sf.dir, "")
  47. if err != nil {
  48. glog.Errorf("create swap file: %v", err)
  49. return nil
  50. }
  51. }
  52. sf.chunkTrackingLock.Lock()
  53. defer sf.chunkTrackingLock.Unlock()
  54. sf.activeChunkCount++
  55. // assign a new physical chunk
  56. var actualChunkIndex ActualChunkIndex
  57. if len(sf.freeActualChunkList) > 0 {
  58. actualChunkIndex = sf.freeActualChunkList[0]
  59. sf.freeActualChunkList = sf.freeActualChunkList[1:]
  60. } else {
  61. actualChunkIndex = ActualChunkIndex(sf.activeChunkCount)
  62. }
  63. swapFileChunk := &SwapFileChunk{
  64. swapfile: sf,
  65. usage: newChunkWrittenIntervalList(),
  66. logicChunkIndex: logicChunkIndex,
  67. actualChunkIndex: actualChunkIndex,
  68. activityScore: NewActivityScore(),
  69. // memChunk: NewMemChunk(logicChunkIndex, sf.chunkSize),
  70. }
  71. // println(logicChunkIndex, "|", "++++", swapFileChunk.actualChunkIndex, swapFileChunk, sf)
  72. return swapFileChunk
  73. }
  74. func (sc *SwapFileChunk) FreeResource() {
  75. sc.Lock()
  76. defer sc.Unlock()
  77. sc.swapfile.chunkTrackingLock.Lock()
  78. defer sc.swapfile.chunkTrackingLock.Unlock()
  79. sc.swapfile.freeActualChunkList = append(sc.swapfile.freeActualChunkList, sc.actualChunkIndex)
  80. sc.swapfile.activeChunkCount--
  81. // println(sc.logicChunkIndex, "|", "----", sc.actualChunkIndex, sc, sc.swapfile)
  82. }
  83. func (sc *SwapFileChunk) WriteDataAt(src []byte, offset int64, tsNs int64) (n int) {
  84. sc.Lock()
  85. defer sc.Unlock()
  86. // println(sc.logicChunkIndex, "|", tsNs, "write at", offset, len(src), sc.actualChunkIndex)
  87. innerOffset := offset % sc.swapfile.chunkSize
  88. var err error
  89. n, err = sc.swapfile.file.WriteAt(src, int64(sc.actualChunkIndex)*sc.swapfile.chunkSize+innerOffset)
  90. sc.usage.MarkWritten(innerOffset, innerOffset+int64(n), tsNs)
  91. if err != nil {
  92. glog.Errorf("failed to write swap file %s: %v", sc.swapfile.file.Name(), err)
  93. }
  94. //sc.memChunk.WriteDataAt(src, offset, tsNs)
  95. sc.activityScore.MarkWrite()
  96. return
  97. }
  98. func (sc *SwapFileChunk) ReadDataAt(p []byte, off int64, tsNs int64) (maxStop int64) {
  99. sc.RLock()
  100. defer sc.RUnlock()
  101. // println(sc.logicChunkIndex, "|", tsNs, "read at", off, len(p), sc.actualChunkIndex)
  102. //memCopy := make([]byte, len(p))
  103. //copy(memCopy, p)
  104. chunkStartOffset := int64(sc.logicChunkIndex) * sc.swapfile.chunkSize
  105. for t := sc.usage.head.next; t != sc.usage.tail; t = t.next {
  106. logicStart := max(off, chunkStartOffset+t.StartOffset)
  107. logicStop := min(off+int64(len(p)), chunkStartOffset+t.stopOffset)
  108. if logicStart < logicStop {
  109. actualStart := logicStart - chunkStartOffset + int64(sc.actualChunkIndex)*sc.swapfile.chunkSize
  110. if _, err := sc.swapfile.file.ReadAt(p[logicStart-off:logicStop-off], actualStart); err != nil {
  111. glog.Errorf("failed to reading swap file %s: %v", sc.swapfile.file.Name(), err)
  112. break
  113. }
  114. maxStop = max(maxStop, logicStop)
  115. if t.TsNs >= tsNs {
  116. println("read new data2", t.TsNs-tsNs, "ns")
  117. }
  118. }
  119. }
  120. //sc.memChunk.ReadDataAt(memCopy, off, tsNs)
  121. //if bytes.Compare(memCopy, p) != 0 {
  122. // println("read wrong data from swap file", off, sc.logicChunkIndex)
  123. //}
  124. sc.activityScore.MarkRead()
  125. return
  126. }
  127. func (sc *SwapFileChunk) IsComplete() bool {
  128. sc.RLock()
  129. defer sc.RUnlock()
  130. return sc.usage.IsComplete(sc.swapfile.chunkSize)
  131. }
  132. func (sc *SwapFileChunk) ActivityScore() int64 {
  133. return sc.activityScore.ActivityScore()
  134. }
  135. func (sc *SwapFileChunk) WrittenSize() int64 {
  136. sc.RLock()
  137. defer sc.RUnlock()
  138. return sc.usage.WrittenSize()
  139. }
  140. func (sc *SwapFileChunk) SaveContent(saveFn SaveToStorageFunc) {
  141. sc.RLock()
  142. defer sc.RUnlock()
  143. if saveFn == nil {
  144. return
  145. }
  146. // println(sc.logicChunkIndex, "|", "save")
  147. for t := sc.usage.head.next; t != sc.usage.tail; t = t.next {
  148. startOffset := t.StartOffset
  149. stopOffset := t.stopOffset
  150. tsNs := t.TsNs
  151. for t != sc.usage.tail && t.next.StartOffset == stopOffset {
  152. stopOffset = t.next.stopOffset
  153. t = t.next
  154. tsNs = max(tsNs, t.TsNs)
  155. }
  156. data := mem.Allocate(int(stopOffset - startOffset))
  157. n, _ := sc.swapfile.file.ReadAt(data, startOffset+int64(sc.actualChunkIndex)*sc.swapfile.chunkSize)
  158. if n > 0 {
  159. reader := util.NewBytesReader(data[:n])
  160. saveFn(reader, int64(sc.logicChunkIndex)*sc.swapfile.chunkSize+startOffset, int64(n), tsNs, func() {
  161. })
  162. }
  163. mem.Free(data)
  164. }
  165. }