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.

368 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. }
  180. }
  181. func TestChunksReading(t *testing.T) {
  182. testcases := []struct {
  183. Chunks []*filer_pb.FileChunk
  184. Offset int64
  185. Size int
  186. Expected []*ChunkView
  187. }{
  188. // case 0: normal
  189. {
  190. Chunks: []*filer_pb.FileChunk{
  191. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  192. {Offset: 100, Size: 100, FileId: "asdf", Mtime: 134},
  193. {Offset: 200, Size: 100, FileId: "fsad", Mtime: 353},
  194. },
  195. Offset: 0,
  196. Size: 250,
  197. Expected: []*ChunkView{
  198. {Offset: 0, Size: 100, FileId: "abc", LogicOffset: 0},
  199. {Offset: 0, Size: 100, FileId: "asdf", LogicOffset: 100},
  200. {Offset: 0, Size: 50, FileId: "fsad", LogicOffset: 200},
  201. },
  202. },
  203. // case 1: updates overwrite full chunks
  204. {
  205. Chunks: []*filer_pb.FileChunk{
  206. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  207. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 134},
  208. },
  209. Offset: 50,
  210. Size: 100,
  211. Expected: []*ChunkView{
  212. {Offset: 50, Size: 100, FileId: "asdf", LogicOffset: 50},
  213. },
  214. },
  215. // case 2: updates overwrite part of previous chunks
  216. {
  217. Chunks: []*filer_pb.FileChunk{
  218. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  219. {Offset: 0, Size: 50, FileId: "asdf", Mtime: 134},
  220. },
  221. Offset: 25,
  222. Size: 50,
  223. Expected: []*ChunkView{
  224. {Offset: 25, Size: 25, FileId: "asdf", LogicOffset: 25},
  225. {Offset: 0, Size: 25, FileId: "abc", LogicOffset: 50},
  226. },
  227. },
  228. // case 3: updates overwrite full chunks
  229. {
  230. Chunks: []*filer_pb.FileChunk{
  231. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  232. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 134},
  233. {Offset: 50, Size: 250, FileId: "xxxx", Mtime: 154},
  234. },
  235. Offset: 0,
  236. Size: 200,
  237. Expected: []*ChunkView{
  238. {Offset: 0, Size: 50, FileId: "asdf", LogicOffset: 0},
  239. {Offset: 0, Size: 150, FileId: "xxxx", LogicOffset: 50},
  240. },
  241. },
  242. // case 4: updates far away from prev chunks
  243. {
  244. Chunks: []*filer_pb.FileChunk{
  245. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  246. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 134},
  247. {Offset: 250, Size: 250, FileId: "xxxx", Mtime: 154},
  248. },
  249. Offset: 0,
  250. Size: 400,
  251. Expected: []*ChunkView{
  252. {Offset: 0, Size: 200, FileId: "asdf", LogicOffset: 0},
  253. // {Offset: 0, Size: 150, FileId: "xxxx"}, // missing intervals should not happen
  254. },
  255. },
  256. // case 5: updates overwrite full chunks
  257. {
  258. Chunks: []*filer_pb.FileChunk{
  259. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  260. {Offset: 0, Size: 200, FileId: "asdf", Mtime: 184},
  261. {Offset: 70, Size: 150, FileId: "abc", Mtime: 143},
  262. {Offset: 80, Size: 100, FileId: "xxxx", Mtime: 134},
  263. },
  264. Offset: 0,
  265. Size: 220,
  266. Expected: []*ChunkView{
  267. {Offset: 0, Size: 200, FileId: "asdf", LogicOffset: 0},
  268. {Offset: 0, Size: 20, FileId: "abc", LogicOffset: 200},
  269. },
  270. },
  271. // case 6: same updates
  272. {
  273. Chunks: []*filer_pb.FileChunk{
  274. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  275. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  276. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  277. },
  278. Offset: 0,
  279. Size: 100,
  280. Expected: []*ChunkView{
  281. {Offset: 0, Size: 100, FileId: "abc", LogicOffset: 0},
  282. },
  283. },
  284. // case 7: edge cases
  285. {
  286. Chunks: []*filer_pb.FileChunk{
  287. {Offset: 0, Size: 100, FileId: "abc", Mtime: 123},
  288. {Offset: 100, Size: 100, FileId: "asdf", Mtime: 134},
  289. {Offset: 200, Size: 100, FileId: "fsad", Mtime: 353},
  290. },
  291. Offset: 0,
  292. Size: 200,
  293. Expected: []*ChunkView{
  294. {Offset: 0, Size: 100, FileId: "abc", LogicOffset: 0},
  295. {Offset: 0, Size: 100, FileId: "asdf", LogicOffset: 100},
  296. },
  297. },
  298. }
  299. for i, testcase := range testcases {
  300. log.Printf("++++++++++ read test case %d ++++++++++++++++++++", i)
  301. chunks := ViewFromChunks(testcase.Chunks, testcase.Offset, testcase.Size)
  302. for x, chunk := range chunks {
  303. log.Printf("read case %d, chunk %d, offset=%d, size=%d, fileId=%s",
  304. i, x, chunk.Offset, chunk.Size, chunk.FileId)
  305. if chunk.Offset != testcase.Expected[x].Offset {
  306. t.Fatalf("failed on read case %d, chunk %d, Offset %d, expect %d",
  307. i, x, chunk.Offset, testcase.Expected[x].Offset)
  308. }
  309. if chunk.Size != testcase.Expected[x].Size {
  310. t.Fatalf("failed on read case %d, chunk %d, Size %d, expect %d",
  311. i, x, chunk.Size, testcase.Expected[x].Size)
  312. }
  313. if chunk.FileId != testcase.Expected[x].FileId {
  314. t.Fatalf("failed on read case %d, chunk %d, FileId %s, expect %s",
  315. i, x, chunk.FileId, testcase.Expected[x].FileId)
  316. }
  317. if chunk.LogicOffset != testcase.Expected[x].LogicOffset {
  318. t.Fatalf("failed on read case %d, chunk %d, LogicOffset %d, expect %d",
  319. i, x, chunk.LogicOffset, testcase.Expected[x].LogicOffset)
  320. }
  321. }
  322. if len(chunks) != len(testcase.Expected) {
  323. t.Fatalf("failed to read test case %d, len %d expected %d", i, len(chunks), len(testcase.Expected))
  324. }
  325. }
  326. }
  327. func BenchmarkCompactFileChunks(b *testing.B) {
  328. var chunks []*filer_pb.FileChunk
  329. k := 1024
  330. for n := 0; n < k; n++ {
  331. chunks = append(chunks, &filer_pb.FileChunk{
  332. Offset: int64(n * 100), Size: 100, FileId: fmt.Sprintf("fileId%d",n), Mtime: int64(n),
  333. })
  334. chunks = append(chunks, &filer_pb.FileChunk{
  335. Offset: int64(n * 50), Size: 100, FileId: fmt.Sprintf("fileId%d",n+k), Mtime: int64(n + k),
  336. })
  337. }
  338. for n := 0; n < b.N; n++ {
  339. CompactFileChunks(chunks)
  340. }
  341. }