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.

370 lines
11 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
6 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
  1. package filer2
  2. import (
  3. "log"
  4. "testing"
  5. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  6. "fmt"
  7. )
  8. func TestCompactFileChunks(t *testing.T) {
  9. chunks := []*filer_pb.FileChunk{
  10. {Offset: 10, Size: 100, FileId: "abc", Mtime: 50},
  11. {Offset: 100, Size: 100, FileId: "def", Mtime: 100},
  12. {Offset: 200, Size: 100, FileId: "ghi", Mtime: 200},
  13. {Offset: 110, Size: 200, FileId: "jkl", Mtime: 300},
  14. }
  15. compacted, garbage := CompactFileChunks(chunks)
  16. if len(compacted) != 3 {
  17. t.Fatalf("unexpected compacted: %d", len(compacted))
  18. }
  19. if len(garbage) != 1 {
  20. t.Fatalf("unexpected garbage: %d", len(garbage))
  21. }
  22. }
  23. func TestCompactFileChunks2(t *testing.T) {
  24. chunks := []*filer_pb.FileChunk{
  25. {Offset: 0, Size: 100, FileId: "abc", Mtime: 50},
  26. {Offset: 100, Size: 100, FileId: "def", Mtime: 100},
  27. {Offset: 200, Size: 100, FileId: "ghi", Mtime: 200},
  28. {Offset: 0, Size: 100, FileId: "abcf", Mtime: 300},
  29. {Offset: 50, Size: 100, FileId: "fhfh", Mtime: 400},
  30. {Offset: 100, Size: 100, FileId: "yuyu", Mtime: 500},
  31. }
  32. k := 3
  33. for n := 0; n < k; n++ {
  34. chunks = append(chunks, &filer_pb.FileChunk{
  35. Offset: int64(n * 100), Size: 100, FileId: fmt.Sprintf("fileId%d",n), Mtime: int64(n),
  36. })
  37. chunks = append(chunks, &filer_pb.FileChunk{
  38. Offset: int64(n * 50), Size: 100, FileId: fmt.Sprintf("fileId%d",n+k), Mtime: int64(n + k),
  39. })
  40. }
  41. compacted, garbage := CompactFileChunks(chunks)
  42. if len(compacted) != 3 {
  43. t.Fatalf("unexpected compacted: %d", len(compacted))
  44. }
  45. if len(garbage) != 9 {
  46. t.Fatalf("unexpected garbage: %d", len(garbage))
  47. }
  48. }
  49. func TestIntervalMerging(t *testing.T) {
  50. testcases := []struct {
  51. Chunks []*filer_pb.FileChunk
  52. Expected []*visibleInterval
  53. }{
  54. // case 0: normal
  55. {
  56. Chunks: []*filer_pb.FileChunk{
  57. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  58. {Offset: 100, Size: 100, FileId: "asdf", Mtime: 134},
  59. {Offset: 200, Size: 100, FileId: "fsad", Mtime: 353},
  60. },
  61. Expected: []*visibleInterval{
  62. {start: 0, stop: 100, fileId: "abc"},
  63. {start: 100, stop: 200, fileId: "asdf"},
  64. {start: 200, stop: 300, fileId: "fsad"},
  65. },
  66. },
  67. // case 1: updates overwrite full chunks
  68. {
  69. Chunks: []*filer_pb.FileChunk{
  70. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  71. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 134},
  72. },
  73. Expected: []*visibleInterval{
  74. {start: 0, stop: 200, fileId: "asdf"},
  75. },
  76. },
  77. // case 2: updates overwrite part of previous chunks
  78. {
  79. Chunks: []*filer_pb.FileChunk{
  80. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  81. {Offset: 0, Size: 50, FileId: "asdf", Mtime: 134},
  82. },
  83. Expected: []*visibleInterval{
  84. {start: 0, stop: 50, fileId: "asdf"},
  85. {start: 50, stop: 100, fileId: "abc"},
  86. },
  87. },
  88. // case 3: updates overwrite full chunks
  89. {
  90. Chunks: []*filer_pb.FileChunk{
  91. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  92. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 134},
  93. {Offset: 50, Size: 250, FileId: "xxxx", Mtime: 154},
  94. },
  95. Expected: []*visibleInterval{
  96. {start: 0, stop: 50, fileId: "asdf"},
  97. {start: 50, stop: 300, fileId: "xxxx"},
  98. },
  99. },
  100. // case 4: updates far away from prev chunks
  101. {
  102. Chunks: []*filer_pb.FileChunk{
  103. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  104. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 134},
  105. {Offset: 250, Size: 250, FileId: "xxxx", Mtime: 154},
  106. },
  107. Expected: []*visibleInterval{
  108. {start: 0, stop: 200, fileId: "asdf"},
  109. {start: 250, stop: 500, fileId: "xxxx"},
  110. },
  111. },
  112. // case 5: updates overwrite full chunks
  113. {
  114. Chunks: []*filer_pb.FileChunk{
  115. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  116. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 184},
  117. {Offset: 70, Size: 150, FileId: "abc", Mtime: 143},
  118. {Offset: 80, Size: 100, FileId: "xxxx", Mtime: 134},
  119. },
  120. Expected: []*visibleInterval{
  121. {start: 0, stop: 200, fileId: "asdf"},
  122. {start: 200, stop: 220, fileId: "abc"},
  123. },
  124. },
  125. // case 6: same updates
  126. {
  127. Chunks: []*filer_pb.FileChunk{
  128. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  129. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  130. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  131. },
  132. Expected: []*visibleInterval{
  133. {start: 0, stop: 100, fileId: "abc"},
  134. },
  135. },
  136. // case 7: real updates
  137. {
  138. Chunks: []*filer_pb.FileChunk{
  139. {Offset: 0, Size: 2097152, FileId: "7,0294cbb9892b", Mtime: 123},
  140. {Offset: 0, Size: 3145728, FileId: "3,029565bf3092", Mtime: 130},
  141. {Offset: 2097152, Size: 3145728, FileId: "6,029632f47ae2", Mtime: 140},
  142. {Offset: 5242880, Size: 3145728, FileId: "2,029734c5aa10", Mtime: 150},
  143. {Offset: 8388608, Size: 3145728, FileId: "5,02982f80de50", Mtime: 160},
  144. {Offset: 11534336, Size: 2842193, FileId: "7,0299ad723803", Mtime: 170},
  145. },
  146. Expected: []*visibleInterval{
  147. {start: 0, stop: 2097152, fileId: "3,029565bf3092"},
  148. {start: 2097152, stop: 5242880, fileId: "6,029632f47ae2"},
  149. {start: 5242880, stop: 8388608, fileId: "2,029734c5aa10"},
  150. {start: 8388608, stop: 11534336, fileId: "5,02982f80de50"},
  151. {start: 11534336, stop: 14376529, fileId: "7,0299ad723803"},
  152. },
  153. },
  154. }
  155. for i, testcase := range testcases {
  156. log.Printf("++++++++++ merged test case %d ++++++++++++++++++++", i)
  157. intervals := nonOverlappingVisibleIntervals(testcase.Chunks)
  158. for x, interval := range intervals {
  159. log.Printf("test case %d, interval %d, start=%d, stop=%d, fileId=%s",
  160. i, x, interval.start, interval.stop, interval.fileId)
  161. }
  162. for x, interval := range intervals {
  163. if interval.start != testcase.Expected[x].start {
  164. t.Fatalf("failed on test case %d, interval %d, start %d, expect %d",
  165. i, x, interval.start, testcase.Expected[x].start)
  166. }
  167. if interval.stop != testcase.Expected[x].stop {
  168. t.Fatalf("failed on test case %d, interval %d, stop %d, expect %d",
  169. i, x, interval.stop, testcase.Expected[x].stop)
  170. }
  171. if interval.fileId != testcase.Expected[x].fileId {
  172. t.Fatalf("failed on test case %d, interval %d, chunkId %s, expect %s",
  173. i, x, interval.fileId, testcase.Expected[x].fileId)
  174. }
  175. }
  176. if len(intervals) != len(testcase.Expected) {
  177. t.Fatalf("failed to compact test case %d, len %d expected %d", i, len(intervals), len(testcase.Expected))
  178. }
  179. cleanupIntervals(intervals)
  180. }
  181. }
  182. func TestChunksReading(t *testing.T) {
  183. testcases := []struct {
  184. Chunks []*filer_pb.FileChunk
  185. Offset int64
  186. Size int
  187. Expected []*ChunkView
  188. }{
  189. // case 0: normal
  190. {
  191. Chunks: []*filer_pb.FileChunk{
  192. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  193. {Offset: 100, Size: 100, FileId: "asdf", Mtime: 134},
  194. {Offset: 200, Size: 100, FileId: "fsad", Mtime: 353},
  195. },
  196. Offset: 0,
  197. Size: 250,
  198. Expected: []*ChunkView{
  199. {Offset: 0, Size: 100, FileId: "abc", LogicOffset: 0},
  200. {Offset: 0, Size: 100, FileId: "asdf", LogicOffset: 100},
  201. {Offset: 0, Size: 50, FileId: "fsad", LogicOffset: 200},
  202. },
  203. },
  204. // case 1: updates overwrite full chunks
  205. {
  206. Chunks: []*filer_pb.FileChunk{
  207. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  208. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 134},
  209. },
  210. Offset: 50,
  211. Size: 100,
  212. Expected: []*ChunkView{
  213. {Offset: 50, Size: 100, FileId: "asdf", LogicOffset: 50},
  214. },
  215. },
  216. // case 2: updates overwrite part of previous chunks
  217. {
  218. Chunks: []*filer_pb.FileChunk{
  219. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  220. {Offset: 0, Size: 50, FileId: "asdf", Mtime: 134},
  221. },
  222. Offset: 25,
  223. Size: 50,
  224. Expected: []*ChunkView{
  225. {Offset: 25, Size: 25, FileId: "asdf", LogicOffset: 25},
  226. {Offset: 0, Size: 25, FileId: "abc", LogicOffset: 50},
  227. },
  228. },
  229. // case 3: updates overwrite full chunks
  230. {
  231. Chunks: []*filer_pb.FileChunk{
  232. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  233. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 134},
  234. {Offset: 50, Size: 250, FileId: "xxxx", Mtime: 154},
  235. },
  236. Offset: 0,
  237. Size: 200,
  238. Expected: []*ChunkView{
  239. {Offset: 0, Size: 50, FileId: "asdf", LogicOffset: 0},
  240. {Offset: 0, Size: 150, FileId: "xxxx", LogicOffset: 50},
  241. },
  242. },
  243. // case 4: updates far away from prev chunks
  244. {
  245. Chunks: []*filer_pb.FileChunk{
  246. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  247. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 134},
  248. {Offset: 250, Size: 250, FileId: "xxxx", Mtime: 154},
  249. },
  250. Offset: 0,
  251. Size: 400,
  252. Expected: []*ChunkView{
  253. {Offset: 0, Size: 200, FileId: "asdf", LogicOffset: 0},
  254. // {Offset: 0, Size: 150, FileId: "xxxx"}, // missing intervals should not happen
  255. },
  256. },
  257. // case 5: updates overwrite full chunks
  258. {
  259. Chunks: []*filer_pb.FileChunk{
  260. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  261. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 184},
  262. {Offset: 70, Size: 150, FileId: "abc", Mtime: 143},
  263. {Offset: 80, Size: 100, FileId: "xxxx", Mtime: 134},
  264. },
  265. Offset: 0,
  266. Size: 220,
  267. Expected: []*ChunkView{
  268. {Offset: 0, Size: 200, FileId: "asdf", LogicOffset: 0},
  269. {Offset: 0, Size: 20, FileId: "abc", LogicOffset: 200},
  270. },
  271. },
  272. // case 6: same updates
  273. {
  274. Chunks: []*filer_pb.FileChunk{
  275. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  276. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  277. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  278. },
  279. Offset: 0,
  280. Size: 100,
  281. Expected: []*ChunkView{
  282. {Offset: 0, Size: 100, FileId: "abc", LogicOffset: 0},
  283. },
  284. },
  285. // case 7: edge cases
  286. {
  287. Chunks: []*filer_pb.FileChunk{
  288. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  289. {Offset: 100, Size: 100, FileId: "asdf", Mtime: 134},
  290. {Offset: 200, Size: 100, FileId: "fsad", Mtime: 353},
  291. },
  292. Offset: 0,
  293. Size: 200,
  294. Expected: []*ChunkView{
  295. {Offset: 0, Size: 100, FileId: "abc", LogicOffset: 0},
  296. {Offset: 0, Size: 100, FileId: "asdf", LogicOffset: 100},
  297. },
  298. },
  299. }
  300. for i, testcase := range testcases {
  301. log.Printf("++++++++++ read test case %d ++++++++++++++++++++", i)
  302. chunks := ViewFromChunks(testcase.Chunks, testcase.Offset, testcase.Size)
  303. for x, chunk := range chunks {
  304. log.Printf("read case %d, chunk %d, offset=%d, size=%d, fileId=%s",
  305. i, x, chunk.Offset, chunk.Size, chunk.FileId)
  306. if chunk.Offset != testcase.Expected[x].Offset {
  307. t.Fatalf("failed on read case %d, chunk %d, Offset %d, expect %d",
  308. i, x, chunk.Offset, testcase.Expected[x].Offset)
  309. }
  310. if chunk.Size != testcase.Expected[x].Size {
  311. t.Fatalf("failed on read case %d, chunk %d, Size %d, expect %d",
  312. i, x, chunk.Size, testcase.Expected[x].Size)
  313. }
  314. if chunk.FileId != testcase.Expected[x].FileId {
  315. t.Fatalf("failed on read case %d, chunk %d, FileId %s, expect %s",
  316. i, x, chunk.FileId, testcase.Expected[x].FileId)
  317. }
  318. if chunk.LogicOffset != testcase.Expected[x].LogicOffset {
  319. t.Fatalf("failed on read case %d, chunk %d, LogicOffset %d, expect %d",
  320. i, x, chunk.LogicOffset, testcase.Expected[x].LogicOffset)
  321. }
  322. }
  323. if len(chunks) != len(testcase.Expected) {
  324. t.Fatalf("failed to read test case %d, len %d expected %d", i, len(chunks), len(testcase.Expected))
  325. }
  326. }
  327. }
  328. func BenchmarkCompactFileChunks(b *testing.B) {
  329. var chunks []*filer_pb.FileChunk
  330. k := 1024
  331. for n := 0; n < k; n++ {
  332. chunks = append(chunks, &filer_pb.FileChunk{
  333. Offset: int64(n * 100), Size: 100, FileId: fmt.Sprintf("fileId%d",n), Mtime: int64(n),
  334. })
  335. chunks = append(chunks, &filer_pb.FileChunk{
  336. Offset: int64(n * 50), Size: 100, FileId: fmt.Sprintf("fileId%d",n+k), Mtime: int64(n + k),
  337. })
  338. }
  339. for n := 0; n < b.N; n++ {
  340. CompactFileChunks(chunks)
  341. }
  342. }