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.

190 lines
5.1 KiB

  1. package filesys
  2. import (
  3. "bytes"
  4. "io"
  5. "math"
  6. "github.com/chrislusf/seaweedfs/weed/glog"
  7. )
  8. type IntervalNode struct {
  9. Data []byte
  10. Offset int64
  11. Size int64
  12. Next *IntervalNode
  13. }
  14. type IntervalLinkedList struct {
  15. Head *IntervalNode
  16. Tail *IntervalNode
  17. }
  18. type ContinuousIntervals struct {
  19. lists []*IntervalLinkedList
  20. }
  21. func (list *IntervalLinkedList) Offset() int64 {
  22. return list.Head.Offset
  23. }
  24. func (list *IntervalLinkedList) Size() int64 {
  25. return list.Tail.Offset + list.Tail.Size - list.Head.Offset
  26. }
  27. func (list *IntervalLinkedList) addNodeToTail(node *IntervalNode) {
  28. // glog.V(0).Infof("add to tail [%d,%d) + [%d,%d) => [%d,%d)", list.Head.Offset, list.Tail.Offset+list.Tail.Size, node.Offset, node.Offset+node.Size, list.Head.Offset, node.Offset+node.Size)
  29. list.Tail.Next = node
  30. list.Tail = node
  31. }
  32. func (list *IntervalLinkedList) addNodeToHead(node *IntervalNode) {
  33. // glog.V(0).Infof("add to head [%d,%d) + [%d,%d) => [%d,%d)", node.Offset, node.Offset+node.Size, list.Head.Offset, list.Tail.Offset+list.Tail.Size, node.Offset, list.Tail.Offset+list.Tail.Size)
  34. node.Next = list.Head
  35. list.Head = node
  36. }
  37. func (list *IntervalLinkedList) ReadData(buf []byte, start, stop int64) {
  38. t := list.Head
  39. for {
  40. nodeStart, nodeStop := max(start, t.Offset), min(stop, t.Offset+t.Size)
  41. if nodeStart < nodeStop {
  42. glog.V(0).Infof("copying start=%d stop=%d t=[%d,%d) t.data=%d => bufSize=%d nodeStart=%d, nodeStop=%d",
  43. start, stop, t.Offset, t.Offset+t.Size, len(t.Data),
  44. len(buf), nodeStart, nodeStop)
  45. copy(buf[nodeStart-start:], t.Data[nodeStart-t.Offset:nodeStop-t.Offset])
  46. }
  47. if t.Next == nil {
  48. break
  49. }
  50. t = t.Next
  51. }
  52. }
  53. func (c *ContinuousIntervals) TotalSize() (total int64) {
  54. for _, list := range c.lists {
  55. total += list.Size()
  56. }
  57. return
  58. }
  59. func (c *ContinuousIntervals) AddInterval(data []byte, offset int64) (hasOverlap bool) {
  60. interval := &IntervalNode{Data: data, Offset: offset, Size: int64(len(data))}
  61. var prevList, nextList *IntervalLinkedList
  62. for _, list := range c.lists {
  63. if list.Head.Offset == interval.Offset+interval.Size {
  64. nextList = list
  65. break
  66. }
  67. }
  68. for _, list := range c.lists {
  69. if list.Head.Offset+list.Size() == offset {
  70. list.addNodeToTail(interval)
  71. prevList = list
  72. break
  73. }
  74. if list.Head.Offset <= offset && offset < list.Head.Offset+list.Size() {
  75. if list.Tail.Offset <= offset {
  76. dataStartIndex := list.Tail.Offset + list.Tail.Size - offset
  77. // glog.V(4).Infof("overlap data new [0,%d) same=%v", dataStartIndex, bytes.Compare(interval.Data[0:dataStartIndex], list.Tail.Data[len(list.Tail.Data)-int(dataStartIndex):]))
  78. interval.Data = interval.Data[dataStartIndex:]
  79. interval.Size -= dataStartIndex
  80. interval.Offset = offset + dataStartIndex
  81. // glog.V(4).Infof("overlapping append as [%d,%d) dataSize=%d", interval.Offset, interval.Offset+interval.Size, len(interval.Data))
  82. list.addNodeToTail(interval)
  83. prevList = list
  84. break
  85. }
  86. glog.V(4).Infof("overlapped! interval is [%d,%d) dataSize=%d", interval.Offset, interval.Offset+interval.Size, len(interval.Data))
  87. hasOverlap = true
  88. return
  89. }
  90. }
  91. if prevList != nil && nextList != nil {
  92. // glog.V(4).Infof("connecting [%d,%d) + [%d,%d) => [%d,%d)", prevList.Head.Offset, prevList.Tail.Offset+prevList.Tail.Size, nextList.Head.Offset, nextList.Tail.Offset+nextList.Tail.Size, prevList.Head.Offset, nextList.Tail.Offset+nextList.Tail.Size)
  93. prevList.Tail.Next = nextList.Head
  94. prevList.Tail = nextList.Tail
  95. c.removeList(nextList)
  96. } else if nextList != nil {
  97. // add to head was not done when checking
  98. nextList.addNodeToHead(interval)
  99. }
  100. if prevList == nil && nextList == nil {
  101. c.lists = append(c.lists, &IntervalLinkedList{
  102. Head: interval,
  103. Tail: interval,
  104. })
  105. }
  106. return
  107. }
  108. func (c *ContinuousIntervals) RemoveLargestIntervalLinkedList() *IntervalLinkedList {
  109. var maxSize int64
  110. maxIndex := -1
  111. for k, list := range c.lists {
  112. if maxSize <= list.Size() {
  113. maxSize = list.Size()
  114. maxIndex = k
  115. }
  116. }
  117. if maxSize <= 0 {
  118. return nil
  119. }
  120. t := c.lists[maxIndex]
  121. c.lists = append(c.lists[0:maxIndex], c.lists[maxIndex+1:]...)
  122. return t
  123. }
  124. func (c *ContinuousIntervals) removeList(target *IntervalLinkedList) {
  125. index := -1
  126. for k, list := range c.lists {
  127. if list.Offset() == target.Offset() {
  128. index = k
  129. }
  130. }
  131. if index < 0 {
  132. return
  133. }
  134. c.lists = append(c.lists[0:index], c.lists[index+1:]...)
  135. }
  136. func (c *ContinuousIntervals) ReadData(data []byte, startOffset int64) (offset int64, size int) {
  137. var minOffset int64 = math.MaxInt64
  138. var maxStop int64
  139. for _, list := range c.lists {
  140. start := max(startOffset, list.Offset())
  141. stop := min(startOffset+int64(len(data)), list.Offset()+list.Size())
  142. if start <= stop {
  143. list.ReadData(data[start-startOffset:], start, stop)
  144. minOffset = min(minOffset, start)
  145. maxStop = max(maxStop, stop)
  146. }
  147. }
  148. if minOffset == math.MaxInt64 {
  149. return 0, 0
  150. }
  151. offset = minOffset
  152. size = int(maxStop - offset)
  153. return
  154. }
  155. func (l *IntervalLinkedList) ToReader() io.Reader {
  156. var readers []io.Reader
  157. t := l.Head
  158. readers = append(readers, bytes.NewReader(t.Data))
  159. for t.Next != nil {
  160. t = t.Next
  161. readers = append(readers, bytes.NewReader(t.Data))
  162. }
  163. return io.MultiReader(readers...)
  164. }