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