gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/host/contractmanager/storagefoldershrink_test.go (about) 1 package contractmanager 2 3 import ( 4 "bytes" 5 "os" 6 "path/filepath" 7 "sync" 8 "sync/atomic" 9 "testing" 10 11 "gitlab.com/SiaPrime/SiaPrime/crypto" 12 "gitlab.com/SiaPrime/SiaPrime/modules" 13 ) 14 15 // TestShrinkStorageFolder checks that a storage folder can be successfully 16 // decreased in size. 17 func TestShrinkStorageFolder(t *testing.T) { 18 if testing.Short() { 19 t.SkipNow() 20 } 21 t.Parallel() 22 cmt, err := newContractManagerTester("TestShrinkStorageFolder") 23 if err != nil { 24 t.Fatal(err) 25 } 26 defer cmt.panicClose() 27 28 // Add a storage folder. 29 storageFolderOne := filepath.Join(cmt.persistDir, "storageFolderOne") 30 // Create the storage folder dir. 31 err = os.MkdirAll(storageFolderOne, 0700) 32 if err != nil { 33 t.Fatal(err) 34 } 35 err = cmt.cm.AddStorageFolder(storageFolderOne, modules.SectorSize*storageFolderGranularity*8) 36 if err != nil { 37 t.Fatal(err) 38 } 39 40 // Get the index of the storage folder. 41 sfs := cmt.cm.StorageFolders() 42 if len(sfs) != 1 { 43 t.Fatal("there should only be one storage folder") 44 } 45 sfIndex := sfs[0].Index 46 // Verify that the storage folder has the correct capacity. 47 if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*8 { 48 t.Error("new storage folder is reporting the wrong capacity") 49 } 50 // Verify that the on-disk files are the right size. 51 mfn := filepath.Join(storageFolderOne, metadataFile) 52 sfn := filepath.Join(storageFolderOne, sectorFile) 53 mfi, err := os.Stat(mfn) 54 if err != nil { 55 t.Fatal(err) 56 } 57 sfi, err := os.Stat(sfn) 58 if err != nil { 59 t.Fatal(err) 60 } 61 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*8 { 62 t.Error("metadata file is the wrong size") 63 } 64 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*8 { 65 t.Error("sector file is the wrong size") 66 } 67 68 // Decrease the size of the storage folder. 69 err = cmt.cm.ResizeStorageFolder(sfIndex, modules.SectorSize*storageFolderGranularity*2, false) 70 if err != nil { 71 t.Fatal(err) 72 } 73 // Verify that the capacity and file sizes are correct. 74 sfs = cmt.cm.StorageFolders() 75 if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*2 { 76 t.Error("new storage folder is reporting the wrong capacity") 77 } 78 mfi, err = os.Stat(mfn) 79 if err != nil { 80 t.Fatal(err) 81 } 82 sfi, err = os.Stat(sfn) 83 if err != nil { 84 t.Fatal(err) 85 } 86 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*2 { 87 t.Error("metadata file is the wrong size") 88 } 89 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*2 { 90 t.Error("sector file is the wrong size") 91 } 92 93 // Restart the contract manager to see that the change is persistent. 94 err = cmt.cm.Close() 95 if err != nil { 96 t.Fatal(err) 97 } 98 cmt.cm, err = New(filepath.Join(cmt.persistDir, modules.ContractManagerDir)) 99 if err != nil { 100 t.Fatal(err) 101 } 102 103 // Verify that the capacity and file sizes are correct. 104 sfs = cmt.cm.StorageFolders() 105 if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*2 { 106 t.Error("new storage folder is reporting the wrong capacity") 107 } 108 mfi, err = os.Stat(mfn) 109 if err != nil { 110 t.Fatal(err) 111 } 112 sfi, err = os.Stat(sfn) 113 if err != nil { 114 t.Fatal(err) 115 } 116 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*2 { 117 t.Error("metadata file is the wrong size") 118 } 119 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*2 { 120 t.Error("sector file is the wrong size") 121 } 122 } 123 124 // TestShrinkStorageFolderWithSectors checks that a storage folder can be 125 // successfully decreased in size when it has sectors which would need to be 126 // moved. 127 func TestShrinkStorageFolderWithSectors(t *testing.T) { 128 if testing.Short() { 129 t.SkipNow() 130 } 131 t.Parallel() 132 cmt, err := newContractManagerTester(t.Name()) 133 if err != nil { 134 t.Fatal(err) 135 } 136 defer cmt.panicClose() 137 138 // Add a storage folder. 139 storageFolderOne := filepath.Join(cmt.persistDir, "storageFolderOne") 140 // Create the storage folder dir. 141 err = os.MkdirAll(storageFolderOne, 0700) 142 if err != nil { 143 t.Fatal(err) 144 } 145 err = cmt.cm.AddStorageFolder(storageFolderOne, modules.SectorSize*storageFolderGranularity*8) 146 if err != nil { 147 t.Fatal(err) 148 } 149 150 // Get the index of the storage folder. 151 sfs := cmt.cm.StorageFolders() 152 if len(sfs) != 1 { 153 t.Fatal("there should only be one storage folder") 154 } 155 sfIndex := sfs[0].Index 156 // Verify that the storage folder has the correct capacity. 157 if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*8 { 158 t.Error("new storage folder is reporting the wrong capacity") 159 } 160 // Verify that the on-disk files are the right size. 161 mfn := filepath.Join(storageFolderOne, metadataFile) 162 sfn := filepath.Join(storageFolderOne, sectorFile) 163 mfi, err := os.Stat(mfn) 164 if err != nil { 165 t.Fatal(err) 166 } 167 sfi, err := os.Stat(sfn) 168 if err != nil { 169 t.Fatal(err) 170 } 171 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*8 { 172 t.Error("metadata file is the wrong size") 173 } 174 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*8 { 175 t.Error("sector file is the wrong size") 176 } 177 178 // Create some sectors and add them to the storage folder. 179 roots := make([]crypto.Hash, storageFolderGranularity*3) 180 datas := make([][]byte, storageFolderGranularity*3) 181 for i := 0; i < storageFolderGranularity*3; i++ { 182 root, data := randSector() 183 roots[i] = root 184 datas[i] = data 185 } 186 // Add all of the sectors. 187 var wg sync.WaitGroup 188 wg.Add(len(roots)) 189 for i := 0; i < len(roots); i++ { 190 go func(i int) { 191 err := cmt.cm.AddSector(roots[i], datas[i]) 192 if err != nil { 193 t.Error(err) 194 } 195 wg.Done() 196 }(i) 197 } 198 wg.Wait() 199 200 // Add a second storage folder so that the displaced sectors have somewhere 201 // to go. 202 storageFolderTwo := filepath.Join(cmt.persistDir, "storageFolderTwo") 203 // Create the storage folder dir. 204 err = os.MkdirAll(storageFolderTwo, 0700) 205 if err != nil { 206 t.Fatal(err) 207 } 208 err = cmt.cm.AddStorageFolder(storageFolderTwo, modules.SectorSize*storageFolderGranularity*3) 209 if err != nil { 210 t.Fatal(err) 211 } 212 213 // Verify that every single sector is readable and has the correct data. 214 wg.Add(len(roots)) 215 var misses uint64 216 for i := 0; i < len(roots); i++ { 217 go func(i int) { 218 data, err := cmt.cm.ReadSector(roots[i]) 219 if err != nil || !bytes.Equal(data, datas[i]) { 220 atomic.AddUint64(&misses, 1) 221 } 222 wg.Done() 223 }(i) 224 } 225 wg.Wait() 226 if misses != 0 { 227 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 228 } 229 230 // Decrease the size of the storage folder. 231 err = cmt.cm.ResizeStorageFolder(sfIndex, modules.SectorSize*storageFolderGranularity*2, false) 232 if err != nil { 233 t.Fatal(err) 234 } 235 // Verify that the capacity and file sizes are correct. 236 sfs = cmt.cm.StorageFolders() 237 capacity := sfs[0].Capacity + sfs[1].Capacity 238 capacityRemaining := sfs[0].CapacityRemaining + sfs[1].CapacityRemaining 239 if capacity != modules.SectorSize*storageFolderGranularity*5 { 240 t.Error("new storage folder is reporting the wrong capacity") 241 } 242 if capacityRemaining != modules.SectorSize*storageFolderGranularity*2 { 243 t.Error("new storage folder capacity remaining is reporting the wrong remaining capacity") 244 } 245 mfi, err = os.Stat(mfn) 246 if err != nil { 247 t.Fatal(err) 248 } 249 sfi, err = os.Stat(sfn) 250 if err != nil { 251 t.Fatal(err) 252 } 253 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*2 { 254 t.Error("metadata file is the wrong size") 255 } 256 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*2 { 257 t.Error("sector file is the wrong size") 258 } 259 260 // Verify that every single sector is readable and has the correct data. 261 wg.Add(len(roots)) 262 misses = 0 263 for i := 0; i < len(roots); i++ { 264 go func(i int) { 265 data, err := cmt.cm.ReadSector(roots[i]) 266 if err != nil || !bytes.Equal(data, datas[i]) { 267 atomic.AddUint64(&misses, 1) 268 } 269 wg.Done() 270 }(i) 271 } 272 wg.Wait() 273 if misses != 0 { 274 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 275 } 276 277 // Restart the contract manager to see that the change is persistent. 278 err = cmt.cm.Close() 279 if err != nil { 280 t.Fatal(err) 281 } 282 cmt.cm, err = New(filepath.Join(cmt.persistDir, modules.ContractManagerDir)) 283 if err != nil { 284 t.Fatal(err) 285 } 286 287 // Verify that the capacity and file sizes are correct. 288 sfs = cmt.cm.StorageFolders() 289 capacity = sfs[0].Capacity + sfs[1].Capacity 290 capacityRemaining = sfs[0].CapacityRemaining + sfs[1].CapacityRemaining 291 if capacity != modules.SectorSize*storageFolderGranularity*5 { 292 t.Error("new storage folder is reporting the wrong capacity") 293 } 294 if capacityRemaining != modules.SectorSize*storageFolderGranularity*2 { 295 t.Error("new storage folder capacity remaining is reporting the wrong remaining capacity") 296 } 297 mfi, err = os.Stat(mfn) 298 if err != nil { 299 t.Fatal(err) 300 } 301 sfi, err = os.Stat(sfn) 302 if err != nil { 303 t.Fatal(err) 304 } 305 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*2 { 306 t.Error("metadata file is the wrong size") 307 } 308 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*2 { 309 t.Error("sector file is the wrong size") 310 } 311 312 // Verify that every single sector is readable and has the correct data. 313 wg.Add(len(roots)) 314 misses = 0 315 for i := 0; i < len(roots); i++ { 316 go func(i int) { 317 data, err := cmt.cm.ReadSector(roots[i]) 318 if err != nil || !bytes.Equal(data, datas[i]) { 319 atomic.AddUint64(&misses, 1) 320 } 321 wg.Done() 322 }(i) 323 } 324 wg.Wait() 325 if misses != 0 { 326 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 327 } 328 } 329 330 // TestShrinkStorageFolderIncopmleteWrite checks that shrinkStorageFolder 331 // operates as intended when the writing to move sectors cannot complete fully. 332 func TestShrinkStorageFolderIncompleteWrite(t *testing.T) { 333 if testing.Short() { 334 t.SkipNow() 335 } 336 t.Parallel() 337 d := new(dependencyIncompleteGrow) 338 cmt, err := newMockedContractManagerTester(d, "TestShrinkStorageFolderIncompleteWrite") 339 if err != nil { 340 t.Fatal(err) 341 } 342 defer cmt.panicClose() 343 344 // Add a storage folder. 345 storageFolderOne := filepath.Join(cmt.persistDir, "storageFolderOne") 346 // Create the storage folder dir. 347 err = os.MkdirAll(storageFolderOne, 0700) 348 if err != nil { 349 t.Fatal(err) 350 } 351 err = cmt.cm.AddStorageFolder(storageFolderOne, modules.SectorSize*storageFolderGranularity*8) 352 if err != nil { 353 t.Fatal(err) 354 } 355 356 // Get the index of the storage folder. 357 sfs := cmt.cm.StorageFolders() 358 if len(sfs) != 1 { 359 t.Fatal("there should only be one storage folder") 360 } 361 sfIndex := sfs[0].Index 362 363 // Create some sectors and add them to the storage folder. 364 roots := make([]crypto.Hash, storageFolderGranularity*3) 365 datas := make([][]byte, storageFolderGranularity*3) 366 for i := 0; i < storageFolderGranularity*3; i++ { 367 root, data := randSector() 368 roots[i] = root 369 datas[i] = data 370 } 371 // Add all of the sectors. 372 var wg sync.WaitGroup 373 wg.Add(len(roots)) 374 for i := 0; i < len(roots); i++ { 375 go func(i int) { 376 err := cmt.cm.AddSector(roots[i], datas[i]) 377 if err != nil { 378 t.Error(err) 379 } 380 wg.Done() 381 }(i) 382 } 383 wg.Wait() 384 385 // Add a second storage folder so that the displaced sectors have somewhere 386 // to go. 387 storageFolderTwo := filepath.Join(cmt.persistDir, "storageFolderTwo") 388 // Create the storage folder dir. 389 err = os.MkdirAll(storageFolderTwo, 0700) 390 if err != nil { 391 t.Fatal(err) 392 } 393 err = cmt.cm.AddStorageFolder(storageFolderTwo, modules.SectorSize*storageFolderGranularity*3) 394 if err != nil { 395 t.Fatal(err) 396 } 397 398 // Trigger some failures. 399 d.mu.Lock() 400 d.threshold = 1 << 15 401 d.triggered = true 402 d.mu.Unlock() 403 404 // Decrease the size of the storage folder. 405 err = cmt.cm.ResizeStorageFolder(sfIndex, modules.SectorSize*storageFolderGranularity*2, false) 406 if err == nil { 407 t.Fatal("expected a failure") 408 } 409 // Verify that the capacity and file sizes are correct. 410 sfs = cmt.cm.StorageFolders() 411 capacity := sfs[0].Capacity + sfs[1].Capacity 412 capacityRemaining := sfs[0].CapacityRemaining + sfs[1].CapacityRemaining 413 if capacity != modules.SectorSize*storageFolderGranularity*11 { 414 t.Error("new storage folder is reporting the wrong capacity") 415 } 416 if capacityRemaining != modules.SectorSize*storageFolderGranularity*8 { 417 t.Error("new storage folder capacity remaining is reporting the wrong remaining capacity") 418 } 419 mfn := filepath.Join(storageFolderOne, metadataFile) 420 sfn := filepath.Join(storageFolderOne, sectorFile) 421 mfi, err := os.Stat(mfn) 422 if err != nil { 423 t.Fatal(err) 424 } 425 sfi, err := os.Stat(sfn) 426 if err != nil { 427 t.Fatal(err) 428 } 429 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*8 { 430 t.Error("metadata file is the wrong size") 431 } 432 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*8 { 433 t.Error("sector file is the wrong size") 434 } 435 436 // Verify that every single sector is readable and has the correct data. 437 wg.Add(len(roots)) 438 var misses uint64 439 for i := 0; i < len(roots); i++ { 440 go func(i int) { 441 data, err := cmt.cm.ReadSector(roots[i]) 442 if err != nil || !bytes.Equal(data, datas[i]) { 443 atomic.AddUint64(&misses, 1) 444 } 445 wg.Done() 446 }(i) 447 } 448 wg.Wait() 449 if misses != 0 { 450 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 451 } 452 453 // Restart the contract manager to see that the change is persistent. 454 err = cmt.cm.Close() 455 if err != nil { 456 t.Fatal(err) 457 } 458 cmt.cm, err = New(filepath.Join(cmt.persistDir, modules.ContractManagerDir)) 459 if err != nil { 460 t.Fatal(err) 461 } 462 463 // Verify that the capacity and file sizes are correct. 464 sfs = cmt.cm.StorageFolders() 465 capacity = sfs[0].Capacity + sfs[1].Capacity 466 capacityRemaining = sfs[0].CapacityRemaining + sfs[1].CapacityRemaining 467 if capacity != modules.SectorSize*storageFolderGranularity*11 { 468 t.Error("new storage folder is reporting the wrong capacity") 469 } 470 if capacityRemaining != modules.SectorSize*storageFolderGranularity*8 { 471 t.Error("new storage folder capacity remaining is reporting the wrong remaining capacity") 472 } 473 mfi, err = os.Stat(mfn) 474 if err != nil { 475 t.Fatal(err) 476 } 477 sfi, err = os.Stat(sfn) 478 if err != nil { 479 t.Fatal(err) 480 } 481 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*8 { 482 t.Error("metadata file is the wrong size") 483 } 484 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*8 { 485 t.Error("sector file is the wrong size") 486 } 487 488 // Verify that every single sector is readable and has the correct data. 489 wg.Add(len(roots)) 490 misses = 0 491 for i := 0; i < len(roots); i++ { 492 go func(i int) { 493 data, err := cmt.cm.ReadSector(roots[i]) 494 if err != nil || !bytes.Equal(data, datas[i]) { 495 atomic.AddUint64(&misses, 1) 496 } 497 wg.Done() 498 }(i) 499 } 500 wg.Wait() 501 if misses != 0 { 502 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 503 } 504 } 505 506 // TestShrinkStorageFolderIncopmleteWriteForce checks that shrinkStorageFolder 507 // operates as intended when the writing to move sectors cannot complete fully, 508 // but the 'force' flag is set. 509 // capacity and capacity remaining. 510 func TestShrinkStorageFolderIncompleteWriteForce(t *testing.T) { 511 if testing.Short() { 512 t.SkipNow() 513 } 514 t.Parallel() 515 d := new(dependencyIncompleteGrow) 516 cmt, err := newMockedContractManagerTester(d, "TestShrinkStorageFolderIncompleteWriteForce") 517 if err != nil { 518 t.Fatal(err) 519 } 520 defer cmt.panicClose() 521 522 // Add a storage folder. 523 storageFolderOne := filepath.Join(cmt.persistDir, "storageFolderOne") 524 // Create the storage folder dir. 525 err = os.MkdirAll(storageFolderOne, 0700) 526 if err != nil { 527 t.Fatal(err) 528 } 529 err = cmt.cm.AddStorageFolder(storageFolderOne, modules.SectorSize*storageFolderGranularity*8) 530 if err != nil { 531 t.Fatal(err) 532 } 533 534 // Get the index of the storage folder. 535 sfs := cmt.cm.StorageFolders() 536 if len(sfs) != 1 { 537 t.Fatal("there should only be one storage folder") 538 } 539 sfIndex := sfs[0].Index 540 541 // Create some sectors and add them to the storage folder. 542 roots := make([]crypto.Hash, 6) 543 datas := make([][]byte, 6) 544 for i := 0; i < len(roots); i++ { 545 root, data := randSector() 546 roots[i] = root 547 datas[i] = data 548 } 549 // Add all of the sectors. 550 var wg sync.WaitGroup 551 wg.Add(len(roots)) 552 for i := 0; i < len(roots); i++ { 553 go func(i int) { 554 err := cmt.cm.AddSector(roots[i], datas[i]) 555 if err != nil { 556 t.Error(err) 557 } 558 wg.Done() 559 }(i) 560 } 561 wg.Wait() 562 563 // Add a second storage folder so that the displaced sectors have somewhere 564 // to go. 565 storageFolderTwo := filepath.Join(cmt.persistDir, "storageFolderTwo") 566 // Create the storage folder dir. 567 err = os.MkdirAll(storageFolderTwo, 0700) 568 if err != nil { 569 t.Fatal(err) 570 } 571 err = cmt.cm.AddStorageFolder(storageFolderTwo, modules.SectorSize*storageFolderGranularity*3) 572 if err != nil { 573 t.Fatal(err) 574 } 575 576 // Trigger some failures. 577 d.mu.Lock() 578 d.threshold = 1 << 11 579 d.triggered = true 580 d.mu.Unlock() 581 582 // Decrease the size of the storage folder. 583 err = cmt.cm.ResizeStorageFolder(sfIndex, modules.SectorSize*storageFolderGranularity*2, true) 584 if err != nil { 585 t.Fatal("expected a failure") 586 } 587 // Verify that the capacity and file sizes are correct. 588 sfs = cmt.cm.StorageFolders() 589 capacity := sfs[0].Capacity + sfs[1].Capacity 590 capacityRemaining := sfs[0].CapacityRemaining + sfs[1].CapacityRemaining 591 if capacity != modules.SectorSize*storageFolderGranularity*5 { 592 t.Error("new storage folder is reporting the wrong capacity") 593 } 594 mfn := filepath.Join(storageFolderOne, metadataFile) 595 sfn := filepath.Join(storageFolderOne, sectorFile) 596 mfi, err := os.Stat(mfn) 597 if err != nil { 598 t.Fatal(err) 599 } 600 sfi, err := os.Stat(sfn) 601 if err != nil { 602 t.Fatal(err) 603 } 604 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*2 { 605 t.Error("metadata file is the wrong size") 606 } 607 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*2 { 608 t.Error("sector file is the wrong size") 609 } 610 611 // Data was lost. Count the number of sectors that are still available. 612 wg.Add(len(roots)) 613 var remainingSectors uint64 614 for i := 0; i < len(roots); i++ { 615 go func(i int) { 616 defer wg.Done() 617 618 data, err := cmt.cm.ReadSector(roots[i]) 619 if err != nil { 620 // Sector probably destroyed. 621 return 622 } 623 if !bytes.Equal(data, datas[i]) { 624 t.Error("ReadSector has returned the wrong data") 625 } 626 627 atomic.AddUint64(&remainingSectors, 1) 628 }(i) 629 } 630 wg.Wait() 631 632 // Check that the capacity remaining matches the number of reachable 633 // sectors. 634 if capacityRemaining != capacity-remainingSectors*modules.SectorSize { 635 t.Error(capacityRemaining/modules.SectorSize, capacity/modules.SectorSize, remainingSectors) 636 } 637 638 // Restart the contract manager to see that the change is persistent. 639 err = cmt.cm.Close() 640 if err != nil { 641 t.Fatal(err) 642 } 643 cmt.cm, err = New(filepath.Join(cmt.persistDir, modules.ContractManagerDir)) 644 if err != nil { 645 t.Fatal(err) 646 } 647 648 // Verify that the capacity and file sizes are correct. 649 sfs = cmt.cm.StorageFolders() 650 capacity = sfs[0].Capacity + sfs[1].Capacity 651 capacityRemaining = sfs[0].CapacityRemaining + sfs[1].CapacityRemaining 652 if capacity != modules.SectorSize*storageFolderGranularity*5 { 653 t.Error("new storage folder is reporting the wrong capacity") 654 } 655 mfi, err = os.Stat(mfn) 656 if err != nil { 657 t.Fatal(err) 658 } 659 sfi, err = os.Stat(sfn) 660 if err != nil { 661 t.Fatal(err) 662 } 663 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*2 { 664 t.Error("metadata file is the wrong size") 665 } 666 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*2 { 667 t.Error("sector file is the wrong size") 668 } 669 670 // Check that the same number of sectors are still available. 671 wg.Add(len(roots)) 672 var nowRemainingSectors uint64 673 for i := 0; i < len(roots); i++ { 674 go func(i int) { 675 defer wg.Done() 676 677 data, err := cmt.cm.ReadSector(roots[i]) 678 if err != nil { 679 // Sector probably destroyed. 680 return 681 } 682 if !bytes.Equal(data, datas[i]) { 683 t.Error("ReadSector has returned the wrong data") 684 } 685 686 atomic.AddUint64(&nowRemainingSectors, 1) 687 }(i) 688 } 689 wg.Wait() 690 691 // Check that the capacity remaining matches the number of reachable 692 // sectors. 693 if capacityRemaining != capacity-remainingSectors*modules.SectorSize { 694 t.Error(capacityRemaining/modules.SectorSize, capacity/modules.SectorSize, remainingSectors) 695 } 696 if remainingSectors != nowRemainingSectors { 697 t.Error("available sector set changed after restart", remainingSectors, nowRemainingSectors) 698 } 699 } 700 701 // dependencyShrinkNoFinalize will not add a confirmation to the WAL that a 702 // shrink storage folder operation has completed. 703 type dependencyShrinkNoFinalize struct { 704 modules.ProductionDependencies 705 } 706 707 // disrupt will prevent the growStorageFolder operation from committing a 708 // finalized growStorageFolder operation to the WAL. 709 func (*dependencyShrinkNoFinalize) Disrupt(s string) bool { 710 if s == "incompleteShrinkStorageFolder" { 711 return true 712 } 713 if s == "cleanWALFile" { 714 return true 715 } 716 return false 717 } 718 719 // TestShrinkStorageFolderShutdownAfterMove simulates an unclean shutdown that 720 // occurs after the storage folder sector move has completed, but before it has 721 // established through the WAL that the move has completed. The result should 722 // be that the storage folder shirnk is not accepted after restart. 723 func TestShrinkStorageFolderShutdownAfterMove(t *testing.T) { 724 if testing.Short() { 725 t.SkipNow() 726 } 727 t.Parallel() 728 d := new(dependencyShrinkNoFinalize) 729 cmt, err := newMockedContractManagerTester(d, "TestShrinkStorageFolderShutdownAfterMove") 730 if err != nil { 731 t.Fatal(err) 732 } 733 defer cmt.panicClose() 734 735 // Add a storage folder. 736 storageFolderOne := filepath.Join(cmt.persistDir, "storageFolderOne") 737 // Create the storage folder dir. 738 err = os.MkdirAll(storageFolderOne, 0700) 739 if err != nil { 740 t.Fatal(err) 741 } 742 err = cmt.cm.AddStorageFolder(storageFolderOne, modules.SectorSize*storageFolderGranularity*8) 743 if err != nil { 744 t.Fatal(err) 745 } 746 747 // Get the index of the storage folder. 748 sfs := cmt.cm.StorageFolders() 749 if len(sfs) != 1 { 750 t.Fatal("there should only be one storage folder") 751 } 752 sfIndex := sfs[0].Index 753 // Verify that the storage folder has the correct capacity. 754 if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*8 { 755 t.Error("new storage folder is reporting the wrong capacity") 756 } 757 // Verify that the on-disk files are the right size. 758 mfn := filepath.Join(storageFolderOne, metadataFile) 759 sfn := filepath.Join(storageFolderOne, sectorFile) 760 mfi, err := os.Stat(mfn) 761 if err != nil { 762 t.Fatal(err) 763 } 764 sfi, err := os.Stat(sfn) 765 if err != nil { 766 t.Fatal(err) 767 } 768 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*8 { 769 t.Error("metadata file is the wrong size") 770 } 771 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*8 { 772 t.Error("sector file is the wrong size") 773 } 774 775 // Create some sectors and add them to the storage folder. 776 roots := make([]crypto.Hash, storageFolderGranularity*3) 777 datas := make([][]byte, storageFolderGranularity*3) 778 for i := 0; i < storageFolderGranularity*3; i++ { 779 root, data := randSector() 780 roots[i] = root 781 datas[i] = data 782 } 783 // Add all of the sectors. 784 var wg sync.WaitGroup 785 wg.Add(len(roots)) 786 for i := 0; i < len(roots); i++ { 787 go func(i int) { 788 err := cmt.cm.AddSector(roots[i], datas[i]) 789 if err != nil { 790 t.Error(err) 791 } 792 wg.Done() 793 }(i) 794 } 795 wg.Wait() 796 797 // Add a second storage folder so that the displaced sectors have somewhere 798 // to go. 799 storageFolderTwo := filepath.Join(cmt.persistDir, "storageFolderTwo") 800 // Create the storage folder dir. 801 err = os.MkdirAll(storageFolderTwo, 0700) 802 if err != nil { 803 t.Fatal(err) 804 } 805 err = cmt.cm.AddStorageFolder(storageFolderTwo, modules.SectorSize*storageFolderGranularity*3) 806 if err != nil { 807 t.Fatal(err) 808 } 809 810 // Verify that every single sector is readable and has the correct data. 811 wg.Add(len(roots)) 812 var misses uint64 813 for i := 0; i < len(roots); i++ { 814 go func(i int) { 815 data, err := cmt.cm.ReadSector(roots[i]) 816 if err != nil || !bytes.Equal(data, datas[i]) { 817 atomic.AddUint64(&misses, 1) 818 } 819 wg.Done() 820 }(i) 821 } 822 wg.Wait() 823 if misses != 0 { 824 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 825 } 826 827 // Decrease the size of the storage folder. 828 err = cmt.cm.ResizeStorageFolder(sfIndex, modules.SectorSize*storageFolderGranularity*2, false) 829 if err != nil { 830 t.Fatal(err) 831 } 832 // Verify that the capacity and file sizes are correct. 833 sfs = cmt.cm.StorageFolders() 834 capacity := sfs[0].Capacity + sfs[1].Capacity 835 capacityRemaining := sfs[0].CapacityRemaining + sfs[1].CapacityRemaining 836 if capacity != modules.SectorSize*storageFolderGranularity*11 { 837 t.Error("new storage folder is reporting the wrong capacity") 838 } 839 if capacityRemaining != modules.SectorSize*storageFolderGranularity*8 { 840 t.Error("new storage folder capacity remaining is reporting the wrong remaining capacity") 841 } 842 mfi, err = os.Stat(mfn) 843 if err != nil { 844 t.Fatal(err) 845 } 846 sfi, err = os.Stat(sfn) 847 if err != nil { 848 t.Fatal(err) 849 } 850 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*8 { 851 t.Error("metadata file is the wrong size") 852 } 853 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*8 { 854 t.Error("sector file is the wrong size") 855 } 856 857 // Verify that every single sector is readable and has the correct data. 858 wg.Add(len(roots)) 859 misses = 0 860 for i := 0; i < len(roots); i++ { 861 go func(i int) { 862 data, err := cmt.cm.ReadSector(roots[i]) 863 if err != nil || !bytes.Equal(data, datas[i]) { 864 atomic.AddUint64(&misses, 1) 865 } 866 wg.Done() 867 }(i) 868 } 869 wg.Wait() 870 if misses != 0 { 871 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 872 } 873 874 // Restart the contract manager. WAL update was not completed, so changes 875 // should not have persisted. All sectors should still be available though, 876 // and they may have moved around but the capacity reporting should align 877 // correctly. 878 err = cmt.cm.Close() 879 if err != nil { 880 t.Fatal(err) 881 } 882 cmt.cm, err = New(filepath.Join(cmt.persistDir, modules.ContractManagerDir)) 883 if err != nil { 884 t.Fatal(err) 885 } 886 887 // Verify that the capacity and file sizes are correct. 888 sfs = cmt.cm.StorageFolders() 889 capacity = sfs[0].Capacity + sfs[1].Capacity 890 capacityRemaining = sfs[0].CapacityRemaining + sfs[1].CapacityRemaining 891 if capacity != modules.SectorSize*storageFolderGranularity*11 { 892 t.Error("new storage folder is reporting the wrong capacity", capacity/modules.SectorSize, storageFolderGranularity*11) 893 } 894 if capacityRemaining != modules.SectorSize*storageFolderGranularity*8 { 895 t.Error("new storage folder capacity remaining is reporting the wrong remaining capacity") 896 } 897 mfi, err = os.Stat(mfn) 898 if err != nil { 899 t.Fatal(err) 900 } 901 sfi, err = os.Stat(sfn) 902 if err != nil { 903 t.Fatal(err) 904 } 905 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*8 { 906 t.Error("metadata file is the wrong size") 907 } 908 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*8 { 909 t.Error("sector file is the wrong size") 910 } 911 912 // Verify that every single sector is readable and has the correct data. 913 wg.Add(len(roots)) 914 misses = 0 915 for i := 0; i < len(roots); i++ { 916 go func(i int) { 917 data, err := cmt.cm.ReadSector(roots[i]) 918 if err != nil || !bytes.Equal(data, datas[i]) { 919 atomic.AddUint64(&misses, 1) 920 } 921 wg.Done() 922 }(i) 923 } 924 wg.Wait() 925 if misses != 0 { 926 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 927 } 928 } 929 930 // TestShrinkStorageFolderWAL completes a storage folder shrinking, but leaves 931 // the WAL behind so that a commit is necessary to finalize things. 932 func TestShrinkStorageFolderWAL(t *testing.T) { 933 if testing.Short() { 934 t.SkipNow() 935 } 936 t.Parallel() 937 d := new(dependencyLeaveWAL) 938 cmt, err := newMockedContractManagerTester(d, "TestShrinkStorageFolderWAL") 939 if err != nil { 940 t.Fatal(err) 941 } 942 defer cmt.panicClose() 943 944 // Add a storage folder. 945 storageFolderOne := filepath.Join(cmt.persistDir, "storageFolderOne") 946 // Create the storage folder dir. 947 err = os.MkdirAll(storageFolderOne, 0700) 948 if err != nil { 949 t.Fatal(err) 950 } 951 err = cmt.cm.AddStorageFolder(storageFolderOne, modules.SectorSize*storageFolderGranularity*8) 952 if err != nil { 953 t.Fatal(err) 954 } 955 956 // Get the index of the storage folder. 957 sfs := cmt.cm.StorageFolders() 958 if len(sfs) != 1 { 959 t.Fatal("there should only be one storage folder") 960 } 961 sfIndex := sfs[0].Index 962 // Verify that the storage folder has the correct capacity. 963 if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*8 { 964 t.Error("new storage folder is reporting the wrong capacity") 965 } 966 // Verify that the on-disk files are the right size. 967 mfn := filepath.Join(storageFolderOne, metadataFile) 968 sfn := filepath.Join(storageFolderOne, sectorFile) 969 mfi, err := os.Stat(mfn) 970 if err != nil { 971 t.Fatal(err) 972 } 973 sfi, err := os.Stat(sfn) 974 if err != nil { 975 t.Fatal(err) 976 } 977 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*8 { 978 t.Error("metadata file is the wrong size") 979 } 980 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*8 { 981 t.Error("sector file is the wrong size") 982 } 983 984 // Create some sectors and add them to the storage folder. 985 roots := make([]crypto.Hash, storageFolderGranularity*3) 986 datas := make([][]byte, storageFolderGranularity*3) 987 for i := 0; i < storageFolderGranularity*3; i++ { 988 root, data := randSector() 989 roots[i] = root 990 datas[i] = data 991 } 992 // Add all of the sectors. 993 var wg sync.WaitGroup 994 wg.Add(len(roots)) 995 for i := 0; i < len(roots); i++ { 996 go func(i int) { 997 err := cmt.cm.AddSector(roots[i], datas[i]) 998 if err != nil { 999 t.Error(err) 1000 } 1001 wg.Done() 1002 }(i) 1003 } 1004 wg.Wait() 1005 1006 // Add a second storage folder so that the displaced sectors have somewhere 1007 // to go. 1008 storageFolderTwo := filepath.Join(cmt.persistDir, "storageFolderTwo") 1009 // Create the storage folder dir. 1010 err = os.MkdirAll(storageFolderTwo, 0700) 1011 if err != nil { 1012 t.Fatal(err) 1013 } 1014 err = cmt.cm.AddStorageFolder(storageFolderTwo, modules.SectorSize*storageFolderGranularity*3) 1015 if err != nil { 1016 t.Fatal(err) 1017 } 1018 1019 // Verify that every single sector is readable and has the correct data. 1020 wg.Add(len(roots)) 1021 var misses uint64 1022 for i := 0; i < len(roots); i++ { 1023 go func(i int) { 1024 data, err := cmt.cm.ReadSector(roots[i]) 1025 if err != nil || !bytes.Equal(data, datas[i]) { 1026 atomic.AddUint64(&misses, 1) 1027 } 1028 wg.Done() 1029 }(i) 1030 } 1031 wg.Wait() 1032 if misses != 0 { 1033 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 1034 } 1035 1036 // Decrease the size of the storage folder. 1037 err = cmt.cm.ResizeStorageFolder(sfIndex, modules.SectorSize*storageFolderGranularity*2, false) 1038 if err != nil { 1039 t.Fatal(err) 1040 } 1041 // Verify that the capacity and file sizes are correct. 1042 sfs = cmt.cm.StorageFolders() 1043 capacity := sfs[0].Capacity + sfs[1].Capacity 1044 capacityRemaining := sfs[0].CapacityRemaining + sfs[1].CapacityRemaining 1045 if capacity != modules.SectorSize*storageFolderGranularity*5 { 1046 t.Error("new storage folder is reporting the wrong capacity") 1047 } 1048 if capacityRemaining != modules.SectorSize*storageFolderGranularity*2 { 1049 t.Error("new storage folder capacity remaining is reporting the wrong remaining capacity") 1050 } 1051 mfi, err = os.Stat(mfn) 1052 if err != nil { 1053 t.Fatal(err) 1054 } 1055 sfi, err = os.Stat(sfn) 1056 if err != nil { 1057 t.Fatal(err) 1058 } 1059 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*2 { 1060 t.Error("metadata file is the wrong size") 1061 } 1062 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*2 { 1063 t.Error("sector file is the wrong size") 1064 } 1065 1066 // Verify that every single sector is readable and has the correct data. 1067 wg.Add(len(roots)) 1068 misses = 0 1069 for i := 0; i < len(roots); i++ { 1070 go func(i int) { 1071 data, err := cmt.cm.ReadSector(roots[i]) 1072 if err != nil || !bytes.Equal(data, datas[i]) { 1073 atomic.AddUint64(&misses, 1) 1074 } 1075 wg.Done() 1076 }(i) 1077 } 1078 wg.Wait() 1079 if misses != 0 { 1080 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 1081 } 1082 1083 // Restart the contract manager to see that the change is persistent. 1084 err = cmt.cm.Close() 1085 if err != nil { 1086 t.Fatal(err) 1087 } 1088 cmt.cm, err = New(filepath.Join(cmt.persistDir, modules.ContractManagerDir)) 1089 if err != nil { 1090 t.Fatal(err) 1091 } 1092 1093 // Verify that the capacity and file sizes are correct. 1094 sfs = cmt.cm.StorageFolders() 1095 capacity = sfs[0].Capacity + sfs[1].Capacity 1096 capacityRemaining = sfs[0].CapacityRemaining + sfs[1].CapacityRemaining 1097 if capacity != modules.SectorSize*storageFolderGranularity*5 { 1098 t.Error("new storage folder is reporting the wrong capacity") 1099 } 1100 if capacityRemaining != modules.SectorSize*storageFolderGranularity*2 { 1101 t.Error("new storage folder capacity remaining is reporting the wrong remaining capacity") 1102 } 1103 mfi, err = os.Stat(mfn) 1104 if err != nil { 1105 t.Fatal(err) 1106 } 1107 sfi, err = os.Stat(sfn) 1108 if err != nil { 1109 t.Fatal(err) 1110 } 1111 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*2 { 1112 t.Error("metadata file is the wrong size") 1113 } 1114 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*2 { 1115 t.Error("sector file is the wrong size") 1116 } 1117 1118 // Verify that every single sector is readable and has the correct data. 1119 wg.Add(len(roots)) 1120 misses = 0 1121 for i := 0; i < len(roots); i++ { 1122 go func(i int) { 1123 data, err := cmt.cm.ReadSector(roots[i]) 1124 if err != nil || !bytes.Equal(data, datas[i]) { 1125 atomic.AddUint64(&misses, 1) 1126 } 1127 wg.Done() 1128 }(i) 1129 } 1130 wg.Wait() 1131 if misses != 0 { 1132 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 1133 } 1134 } 1135 1136 // TestShrinkSingleStorageFolder verifies that it's possible to shirnk a single 1137 // storage folder with no destination for the sectors. 1138 func TestShrinkSingleStorageFolder(t *testing.T) { 1139 // TODO: Supporting in-place storage folder shrinking requires the 1140 // move-sector function to be able to recognize the storage folder that it 1141 // is currently using - right now it needs a storage folder lock to migrate 1142 // a sector in, and a storage folder lock to migrate a sector out, and 1143 // these locks are independent, so it cannot move a sector into the folder 1144 // that the sector is being moved out of. 1145 t.Skip("In-place shrinking not currently supported") 1146 if testing.Short() { 1147 t.SkipNow() 1148 } 1149 t.Parallel() 1150 cmt, err := newContractManagerTester(t.Name()) 1151 if err != nil { 1152 t.Fatal(err) 1153 } 1154 defer cmt.panicClose() 1155 1156 // Add a storage folder. 1157 storageFolderOne := filepath.Join(cmt.persistDir, "storageFolderOne") 1158 mfn := filepath.Join(storageFolderOne, metadataFile) 1159 sfn := filepath.Join(storageFolderOne, sectorFile) 1160 // Create the storage folder dir. 1161 err = os.MkdirAll(storageFolderOne, 0700) 1162 if err != nil { 1163 t.Fatal(err) 1164 } 1165 err = cmt.cm.AddStorageFolder(storageFolderOne, modules.SectorSize*storageFolderGranularity*8) 1166 if err != nil { 1167 t.Fatal(err) 1168 } 1169 // Get the index of the storage folder. 1170 sfs := cmt.cm.StorageFolders() 1171 if len(sfs) != 1 { 1172 t.Fatal("there should only be one storage folder") 1173 } 1174 sfIndex := sfs[0].Index 1175 1176 // Create some sectors and add them to the storage folder. 1177 roots := make([]crypto.Hash, storageFolderGranularity*3) 1178 datas := make([][]byte, storageFolderGranularity*3) 1179 for i := 0; i < storageFolderGranularity*3; i++ { 1180 root, data := randSector() 1181 roots[i] = root 1182 datas[i] = data 1183 } 1184 // Add all of the sectors. 1185 var wg sync.WaitGroup 1186 wg.Add(len(roots)) 1187 for i := 0; i < len(roots); i++ { 1188 go func(i int) { 1189 err := cmt.cm.AddSector(roots[i], datas[i]) 1190 if err != nil { 1191 t.Error(err) 1192 } 1193 wg.Done() 1194 }(i) 1195 } 1196 wg.Wait() 1197 1198 // Decrease the size of the storage folder. 1199 err = cmt.cm.ResizeStorageFolder(sfIndex, modules.SectorSize*storageFolderGranularity*4, false) 1200 if err != nil { 1201 t.Fatal(err) 1202 } 1203 // Verify that the capacity and file sizes are correct. 1204 sfs = cmt.cm.StorageFolders() 1205 if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*4 { 1206 t.Error("new storage folder is reporting the wrong capacity") 1207 } 1208 if sfs[0].CapacityRemaining != modules.SectorSize*storageFolderGranularity*1 { 1209 t.Error("new storage folder capacity remaining is reporting the wrong remaining capacity") 1210 } 1211 mfi, err := os.Stat(mfn) 1212 if err != nil { 1213 t.Fatal(err) 1214 } 1215 sfi, err := os.Stat(sfn) 1216 if err != nil { 1217 t.Fatal(err) 1218 } 1219 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*4 { 1220 t.Error("metadata file is the wrong size") 1221 } 1222 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*4 { 1223 t.Error("sector file is the wrong size") 1224 } 1225 1226 // Verify that every single sector is readable and has the correct data. 1227 wg.Add(len(roots)) 1228 misses := uint64(0) 1229 for i := 0; i < len(roots); i++ { 1230 go func(i int) { 1231 data, err := cmt.cm.ReadSector(roots[i]) 1232 if err != nil || !bytes.Equal(data, datas[i]) { 1233 atomic.AddUint64(&misses, 1) 1234 } 1235 wg.Done() 1236 }(i) 1237 } 1238 wg.Wait() 1239 if misses != 0 { 1240 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 1241 } 1242 1243 // Restart the contract manager to see that the change is persistent. 1244 err = cmt.cm.Close() 1245 if err != nil { 1246 t.Fatal(err) 1247 } 1248 cmt.cm, err = New(filepath.Join(cmt.persistDir, modules.ContractManagerDir)) 1249 if err != nil { 1250 t.Fatal(err) 1251 } 1252 1253 // Verify that the capacity and file sizes are correct. 1254 sfs = cmt.cm.StorageFolders() 1255 if sfs[0].Capacity != modules.SectorSize*storageFolderGranularity*4 { 1256 t.Error("new storage folder is reporting the wrong capacity") 1257 } 1258 if sfs[0].CapacityRemaining != modules.SectorSize*storageFolderGranularity*1 { 1259 t.Error("new storage folder capacity remaining is reporting the wrong remaining capacity") 1260 } 1261 mfi, err = os.Stat(mfn) 1262 if err != nil { 1263 t.Fatal(err) 1264 } 1265 sfi, err = os.Stat(sfn) 1266 if err != nil { 1267 t.Fatal(err) 1268 } 1269 if uint64(mfi.Size()) != sectorMetadataDiskSize*storageFolderGranularity*4 { 1270 t.Error("metadata file is the wrong size") 1271 } 1272 if uint64(sfi.Size()) != modules.SectorSize*storageFolderGranularity*4 { 1273 t.Error("sector file is the wrong size") 1274 } 1275 1276 // Verify that every single sector is readable and has the correct data. 1277 wg.Add(len(roots)) 1278 misses = 0 1279 for i := 0; i < len(roots); i++ { 1280 go func(i int) { 1281 data, err := cmt.cm.ReadSector(roots[i]) 1282 if err != nil || !bytes.Equal(data, datas[i]) { 1283 atomic.AddUint64(&misses, 1) 1284 } 1285 wg.Done() 1286 }(i) 1287 } 1288 wg.Wait() 1289 if misses != 0 { 1290 t.Errorf("Could not find all %v sectors: %v\n", len(roots), misses) 1291 } 1292 }