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.

175 lines
3.8 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
6 years ago
7 years ago
6 years ago
7 years ago
6 years ago
7 years ago
6 years ago
7 years ago
6 years ago
7 years ago
6 years ago
7 years ago
6 years ago
7 years ago
6 years ago
7 years ago
  1. package filer2
  2. import (
  3. "fmt"
  4. "hash/fnv"
  5. "sort"
  6. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  7. )
  8. func TotalSize(chunks []*filer_pb.FileChunk) (size uint64) {
  9. for _, c := range chunks {
  10. t := uint64(c.Offset + int64(c.Size))
  11. if size < t {
  12. size = t
  13. }
  14. }
  15. return
  16. }
  17. func ETag(chunks []*filer_pb.FileChunk) (etag string) {
  18. if len(chunks) == 1 {
  19. return chunks[0].ETag
  20. }
  21. h := fnv.New32a()
  22. for _, c := range chunks {
  23. h.Write([]byte(c.ETag))
  24. }
  25. return fmt.Sprintf("%x", h.Sum32())
  26. }
  27. func CompactFileChunks(chunks []*filer_pb.FileChunk) (compacted, garbage []*filer_pb.FileChunk) {
  28. visibles := nonOverlappingVisibleIntervals(chunks)
  29. fileIds := make(map[string]bool)
  30. for _, interval := range visibles {
  31. fileIds[interval.fileId] = true
  32. }
  33. for _, chunk := range chunks {
  34. if found := fileIds[chunk.FileId]; found {
  35. compacted = append(compacted, chunk)
  36. } else {
  37. garbage = append(garbage, chunk)
  38. }
  39. }
  40. return
  41. }
  42. func FindUnusedFileChunks(oldChunks, newChunks []*filer_pb.FileChunk) (unused []*filer_pb.FileChunk) {
  43. fileIds := make(map[string]bool)
  44. for _, interval := range newChunks {
  45. fileIds[interval.FileId] = true
  46. }
  47. for _, chunk := range oldChunks {
  48. if found := fileIds[chunk.FileId]; !found {
  49. unused = append(unused, chunk)
  50. }
  51. }
  52. return
  53. }
  54. type ChunkView struct {
  55. FileId string
  56. Offset int64
  57. Size uint64
  58. LogicOffset int64
  59. }
  60. func ViewFromChunks(chunks []*filer_pb.FileChunk, offset int64, size int) (views []*ChunkView) {
  61. visibles := nonOverlappingVisibleIntervals(chunks)
  62. stop := offset + int64(size)
  63. for _, chunk := range visibles {
  64. if chunk.start <= offset && offset < chunk.stop && offset < stop {
  65. views = append(views, &ChunkView{
  66. FileId: chunk.fileId,
  67. Offset: offset - chunk.start, // offset is the data starting location in this file id
  68. Size: uint64(min(chunk.stop, stop) - offset),
  69. LogicOffset: offset,
  70. })
  71. offset = min(chunk.stop, stop)
  72. }
  73. }
  74. return views
  75. }
  76. func logPrintf(name string, visibles []*visibleInterval) {
  77. /*
  78. log.Printf("%s len %d", name, len(visibles))
  79. for _, v := range visibles {
  80. log.Printf("%s: => %+v", name, v)
  81. }
  82. */
  83. }
  84. func mergeIntoVisibles(visibles []*visibleInterval, chunk *filer_pb.FileChunk) (newVisibles []*visibleInterval) {
  85. for _, v := range visibles {
  86. if v.start < chunk.Offset && chunk.Offset < v.stop {
  87. newVisibles = append(newVisibles, newVisibleInterval(
  88. v.start,
  89. chunk.Offset,
  90. v.fileId,
  91. v.modifiedTime,
  92. ))
  93. }
  94. chunkStop := chunk.Offset + int64(chunk.Size)
  95. if v.start < chunkStop && chunkStop < v.stop {
  96. newVisibles = append(newVisibles, newVisibleInterval(
  97. chunkStop,
  98. v.stop,
  99. v.fileId,
  100. v.modifiedTime,
  101. ))
  102. }
  103. if chunkStop < v.start || v.stop <= chunk.Offset {
  104. newVisibles = append(newVisibles, v)
  105. }
  106. }
  107. newVisibles = append(newVisibles, newVisibleInterval(
  108. chunk.Offset,
  109. chunk.Offset+int64(chunk.Size),
  110. chunk.FileId,
  111. chunk.Mtime,
  112. ))
  113. return
  114. }
  115. func nonOverlappingVisibleIntervals(chunks []*filer_pb.FileChunk) (visibles []*visibleInterval) {
  116. sort.Slice(chunks, func(i, j int) bool {
  117. return chunks[i].Mtime < chunks[j].Mtime
  118. })
  119. for _, chunk := range chunks {
  120. visibles = mergeIntoVisibles(visibles, chunk)
  121. }
  122. sort.Slice(visibles, func(i, j int) bool {
  123. return visibles[i].start < visibles[j].start
  124. })
  125. logPrintf("visibles", visibles)
  126. return
  127. }
  128. // find non-overlapping visible intervals
  129. // visible interval map to one file chunk
  130. type visibleInterval struct {
  131. start int64
  132. stop int64
  133. modifiedTime int64
  134. fileId string
  135. }
  136. func newVisibleInterval(start, stop int64, fileId string, modifiedTime int64) *visibleInterval {
  137. return &visibleInterval{start: start, stop: stop, fileId: fileId, modifiedTime: modifiedTime}
  138. }
  139. func min(x, y int64) int64 {
  140. if x <= y {
  141. return x
  142. }
  143. return y
  144. }