github.com/rohankumardubey/proxyfs@v0.0.0-20210108201508-653efa9ab00e/inode/coalesce_test.go (about) 1 package inode 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/stretchr/testify/assert" 8 "github.com/swiftstack/ProxyFS/blunder" 9 ) 10 11 // NB: test setup and such is in api_test.go (look for TestMain function) 12 13 func TestCoalesce(t *testing.T) { 14 testSetup(t, false) 15 16 // We're going to take some files: 17 // 18 // d1/file1a (contents "abcd") 19 // d1/file1b (contents "efgh") 20 // d2/file2a (contents "ijkl") 21 // d2/file2b (contents "mnop") 22 // d2/file2c (contents "\0\0st\0\0") 23 // 24 // and coalesce them into a single file: 25 // 26 // d1/combined (contents "abcdefghijklmnop\0\0st\0\0") 27 // 28 // This will also unlink the constituent files from their directories. 29 30 assert := assert.New(t) 31 vh, err := FetchVolumeHandle("TestVolume") 32 if !assert.Nil(err) { 33 return 34 } 35 36 d1InodeNumber, err := vh.CreateDir(PosixModePerm, 0, 0) 37 if !assert.Nil(err) { 38 return 39 } 40 err = vh.Link(RootDirInodeNumber, "d1", d1InodeNumber, false) 41 if !assert.Nil(err) { 42 return 43 } 44 45 d2InodeNumber, err := vh.CreateDir(PosixModePerm, 0, 0) 46 if !assert.Nil(err) { 47 return 48 } 49 err = vh.Link(RootDirInodeNumber, "d2", d2InodeNumber, false) 50 if !assert.Nil(err) { 51 return 52 } 53 54 file1aInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 55 if !assert.Nil(err) { 56 return 57 } 58 err = vh.Write(file1aInodeNumber, 0, []byte("abcd"), nil) 59 if !assert.Nil(err) { 60 return 61 } 62 err = vh.Link(d1InodeNumber, "file1a", file1aInodeNumber, false) 63 if !assert.Nil(err) { 64 return 65 } 66 67 file1bInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 68 if !assert.Nil(err) { 69 return 70 } 71 err = vh.Write(file1bInodeNumber, 0, []byte("efgh"), nil) 72 if !assert.Nil(err) { 73 return 74 } 75 err = vh.Link(d1InodeNumber, "file1b", file1bInodeNumber, false) 76 if !assert.Nil(err) { 77 return 78 } 79 80 file2aInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 81 if !assert.Nil(err) { 82 return 83 } 84 err = vh.Write(file2aInodeNumber, 0, []byte("ijkl"), nil) 85 if !assert.Nil(err) { 86 return 87 } 88 err = vh.Link(d2InodeNumber, "file2a", file2aInodeNumber, false) 89 if !assert.Nil(err) { 90 return 91 } 92 93 file2bInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 94 if !assert.Nil(err) { 95 return 96 } 97 err = vh.Write(file2bInodeNumber, 0, []byte("mnop"), nil) 98 if !assert.Nil(err) { 99 return 100 } 101 err = vh.Link(d2InodeNumber, "file2b", file2bInodeNumber, false) 102 if !assert.Nil(err) { 103 return 104 } 105 106 // Note that this one is sparse: the first 2 bytes are 0, then we have "st", then 2 more 0s 107 file2cInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 108 if !assert.Nil(err) { 109 return 110 } 111 err = vh.Write(file2cInodeNumber, 2, []byte("st"), nil) 112 if !assert.Nil(err) { 113 return 114 } 115 err = vh.Link(d2InodeNumber, "file2c", file2cInodeNumber, false) 116 if !assert.Nil(err) { 117 return 118 } 119 err = vh.SetSize(file2cInodeNumber, 6) 120 if !assert.Nil(err) { 121 return 122 } 123 124 // Now create destination file 125 combinedInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 126 if !assert.Nil(err) { 127 return 128 } 129 err = vh.Link(d1InodeNumber, "combined", combinedInodeNumber, false) 130 if !assert.Nil(err) { 131 return 132 } 133 134 // test setup's done; now we can coalesce things 135 elements := make([]*CoalesceElement, 0, 5) 136 elements = append(elements, &CoalesceElement{ 137 ContainingDirectoryInodeNumber: d1InodeNumber, 138 ElementInodeNumber: file1aInodeNumber, 139 ElementName: "file1a"}) 140 elements = append(elements, &CoalesceElement{ 141 ContainingDirectoryInodeNumber: d1InodeNumber, 142 ElementInodeNumber: file1bInodeNumber, 143 ElementName: "file1b"}) 144 elements = append(elements, &CoalesceElement{ 145 ContainingDirectoryInodeNumber: d2InodeNumber, 146 ElementInodeNumber: file2aInodeNumber, 147 ElementName: "file2a"}) 148 elements = append(elements, &CoalesceElement{ 149 ContainingDirectoryInodeNumber: d2InodeNumber, 150 ElementInodeNumber: file2bInodeNumber, 151 ElementName: "file2b"}) 152 elements = append(elements, &CoalesceElement{ 153 ContainingDirectoryInodeNumber: d2InodeNumber, 154 ElementInodeNumber: file2cInodeNumber, 155 ElementName: "file2c"}) 156 157 newMetaData := []byte("The quick brown fox jumped over the lazy dog.") 158 159 // Coalesce the above 5 files and metadata into d1/combined 160 startTime := time.Now() 161 attrChangeTime, modificationTime, numWrites, fileSize, err := vh.Coalesce( 162 combinedInodeNumber, "MetaDataStream", newMetaData, elements) 163 if !assert.Nil(err) { 164 return 165 } 166 assert.Equal(uint64(22), fileSize) 167 assert.Equal(uint64(5), numWrites) 168 assert.Equal(attrChangeTime, modificationTime) 169 assert.True(attrChangeTime.After(startTime)) 170 171 // The new file has the contents of the old files combined 172 contents, err := vh.Read(combinedInodeNumber, 0, 22, nil) 173 if !assert.Nil(err) { 174 return 175 } 176 assert.Equal([]byte("abcdefghijklmnop\x00\x00st\x00\x00"), contents) 177 178 // The old files have ceased to be 179 _, err = vh.Lookup(d1InodeNumber, "file1a") 180 assert.True(blunder.Is(err, blunder.NotFoundError)) 181 _, err = vh.Lookup(d1InodeNumber, "file1b") 182 assert.True(blunder.Is(err, blunder.NotFoundError)) 183 _, err = vh.Lookup(d2InodeNumber, "file2a") 184 assert.True(blunder.Is(err, blunder.NotFoundError)) 185 _, err = vh.Lookup(d2InodeNumber, "file2b") 186 assert.True(blunder.Is(err, blunder.NotFoundError)) 187 _, err = vh.Lookup(d2InodeNumber, "file2c") 188 assert.True(blunder.Is(err, blunder.NotFoundError)) 189 190 // The new file is linked in at the right spot 191 foundInodeNumber, err := vh.Lookup(d1InodeNumber, "combined") 192 if !assert.Nil(err) { 193 return 194 } 195 assert.Equal(combinedInodeNumber, foundInodeNumber) 196 197 // Verify the new file has the new metadata 198 buf, err := vh.GetStream(combinedInodeNumber, "MetaDataStream") 199 if assert.Nil(err) { 200 assert.Equal(buf, newMetaData) 201 } 202 203 testTeardown(t) 204 } 205 206 func TestCoalesceDir(t *testing.T) { 207 testSetup(t, false) 208 209 // We're going to take some files: 210 // 211 // d1/file1a (contents "abcd") 212 // d1/file1b (contents "efgh") 213 // 214 // and attempt to coalesce them into a directory: 215 // 216 // d1 217 218 assert := assert.New(t) 219 vh, err := FetchVolumeHandle("TestVolume") 220 if !assert.Nil(err) { 221 return 222 } 223 224 d1InodeNumber, err := vh.CreateDir(PosixModePerm, 0, 0) 225 if !assert.Nil(err) { 226 return 227 } 228 err = vh.Link(RootDirInodeNumber, "d1", d1InodeNumber, false) 229 if !assert.Nil(err) { 230 return 231 } 232 233 file1aInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 234 if !assert.Nil(err) { 235 return 236 } 237 err = vh.Write(file1aInodeNumber, 0, []byte("abcd"), nil) 238 if !assert.Nil(err) { 239 return 240 } 241 err = vh.Link(d1InodeNumber, "file1a", file1aInodeNumber, false) 242 if !assert.Nil(err) { 243 return 244 } 245 246 file1bInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 247 if !assert.Nil(err) { 248 return 249 } 250 err = vh.Write(file1bInodeNumber, 0, []byte("efgh"), nil) 251 if !assert.Nil(err) { 252 return 253 } 254 err = vh.Link(d1InodeNumber, "file1b", file1bInodeNumber, false) 255 if !assert.Nil(err) { 256 return 257 } 258 259 // test setup's done; now we can coalesce things 260 elements := make([]*CoalesceElement, 0, 2) 261 elements = append(elements, &CoalesceElement{ 262 ContainingDirectoryInodeNumber: d1InodeNumber, 263 ElementInodeNumber: file1aInodeNumber, 264 ElementName: "file1a"}) 265 elements = append(elements, &CoalesceElement{ 266 ContainingDirectoryInodeNumber: d1InodeNumber, 267 ElementInodeNumber: file1bInodeNumber, 268 ElementName: "file1b"}) 269 270 // Coalesce the above 2 files into d1 271 _, _, _, _, err = vh.Coalesce(d1InodeNumber, "MetaDataStream", nil, elements) 272 assert.NotNil(err) 273 assert.True(blunder.Is(err, blunder.PermDeniedError)) 274 275 testTeardown(t) 276 } 277 278 func TestCoalesceMultipleLinks(t *testing.T) { 279 testSetup(t, false) 280 281 // We're going to take hard-linked files: 282 // 283 // d1/file1a (contents "abcd") 284 // d1/file1b (hard-linked to d1/file1a) 285 // 286 // and attempt to coalesce them into a single file: 287 // 288 // d1/combined 289 290 assert := assert.New(t) 291 vh, err := FetchVolumeHandle("TestVolume") 292 if !assert.Nil(err) { 293 return 294 } 295 296 d1InodeNumber, err := vh.CreateDir(PosixModePerm, 0, 0) 297 if !assert.Nil(err) { 298 return 299 } 300 err = vh.Link(RootDirInodeNumber, "d1", d1InodeNumber, false) 301 if !assert.Nil(err) { 302 return 303 } 304 305 file1aInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 306 if !assert.Nil(err) { 307 return 308 } 309 err = vh.Write(file1aInodeNumber, 0, []byte("abcd"), nil) 310 if !assert.Nil(err) { 311 return 312 } 313 err = vh.Link(d1InodeNumber, "file1a", file1aInodeNumber, false) 314 if !assert.Nil(err) { 315 return 316 } 317 318 file1bInodeNumber := file1aInodeNumber 319 err = vh.Link(d1InodeNumber, "file1b", file1bInodeNumber, false) 320 if !assert.Nil(err) { 321 return 322 } 323 324 // Now create destination file 325 combinedInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 326 if !assert.Nil(err) { 327 return 328 } 329 err = vh.Link(d1InodeNumber, "combined", combinedInodeNumber, false) 330 if !assert.Nil(err) { 331 return 332 } 333 334 // test setup's done; now we can coalesce things 335 elements := make([]*CoalesceElement, 0, 2) 336 elements = append(elements, &CoalesceElement{ 337 ContainingDirectoryInodeNumber: d1InodeNumber, 338 ElementInodeNumber: file1aInodeNumber, 339 ElementName: "file1a"}) 340 elements = append(elements, &CoalesceElement{ 341 ContainingDirectoryInodeNumber: d1InodeNumber, 342 ElementInodeNumber: file1bInodeNumber, 343 ElementName: "file1b"}) 344 345 // Coalesce the above 2 files into d1/combined 346 _, _, _, _, err = vh.Coalesce(combinedInodeNumber, "MetaDataStream", nil, elements) 347 assert.NotNil(err) 348 assert.True(blunder.Is(err, blunder.TooManyLinksError)) 349 350 testTeardown(t) 351 } 352 353 func TestCoalesceDuplicates(t *testing.T) { 354 testSetup(t, false) 355 356 // We're going to take hard-linked files: 357 // 358 // d1/file1a (contents "abcd") 359 // d1/file1b (contents "efgh") 360 // d1/file1a (again) 361 // 362 // and attempt to coalesce them into a single file: 363 // 364 // d1/combined 365 366 assert := assert.New(t) 367 vh, err := FetchVolumeHandle("TestVolume") 368 if !assert.Nil(err) { 369 return 370 } 371 372 d1InodeNumber, err := vh.CreateDir(PosixModePerm, 0, 0) 373 if !assert.Nil(err) { 374 return 375 } 376 err = vh.Link(RootDirInodeNumber, "d1", d1InodeNumber, false) 377 if !assert.Nil(err) { 378 return 379 } 380 381 file1aInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 382 if !assert.Nil(err) { 383 return 384 } 385 err = vh.Write(file1aInodeNumber, 0, []byte("abcd"), nil) 386 if !assert.Nil(err) { 387 return 388 } 389 err = vh.Link(d1InodeNumber, "file1a", file1aInodeNumber, false) 390 if !assert.Nil(err) { 391 return 392 } 393 394 file1bInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 395 if !assert.Nil(err) { 396 return 397 } 398 err = vh.Write(file1bInodeNumber, 0, []byte("efgh"), nil) 399 if !assert.Nil(err) { 400 return 401 } 402 err = vh.Link(d1InodeNumber, "file1b", file1bInodeNumber, false) 403 if !assert.Nil(err) { 404 return 405 } 406 407 // Now create destination file 408 combinedInodeNumber, err := vh.CreateFile(PosixModePerm, 0, 0) 409 if !assert.Nil(err) { 410 return 411 } 412 err = vh.Link(d1InodeNumber, "combined", combinedInodeNumber, false) 413 if !assert.Nil(err) { 414 return 415 } 416 417 // test setup's done; now we can coalesce things 418 elements := make([]*CoalesceElement, 0, 3) 419 elements = append(elements, &CoalesceElement{ 420 ContainingDirectoryInodeNumber: d1InodeNumber, 421 ElementInodeNumber: file1aInodeNumber, 422 ElementName: "file1a"}) 423 elements = append(elements, &CoalesceElement{ 424 ContainingDirectoryInodeNumber: d1InodeNumber, 425 ElementInodeNumber: file1bInodeNumber, 426 ElementName: "file1b"}) 427 elements = append(elements, &CoalesceElement{ 428 ContainingDirectoryInodeNumber: d1InodeNumber, 429 ElementInodeNumber: file1aInodeNumber, 430 ElementName: "file1a"}) 431 432 // Coalesce the above 3 files into d1/combined 433 _, _, _, _, err = vh.Coalesce(combinedInodeNumber, "MetaDataStream", nil, elements) 434 assert.NotNil(err) 435 assert.True(blunder.Is(err, blunder.InvalidArgError)) 436 437 testTeardown(t) 438 }