github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/host/storagemanager/storagefolders_smoke_test.go (about) 1 package storagemanager 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "testing" 11 12 "github.com/NebulousLabs/Sia/crypto" 13 "github.com/NebulousLabs/Sia/modules" 14 "github.com/NebulousLabs/Sia/types" 15 16 "github.com/NebulousLabs/bolt" 17 ) 18 19 // sectorUsageCheck compares a manually maintained sector usage map to the 20 // manager's internal sector usage map, and returns an error if there are any 21 // inconsistencies. 22 func (smt *storageManagerTester) sectorUsageCheck(sectorUsageMap map[crypto.Hash][]types.BlockHeight) error { 23 // Check that the in-database representation for the sector usage map 24 // matches the in-memory understanding of what the sector map should be 25 return smt.sm.db.View(func(tx *bolt.Tx) error { 26 bsu := tx.Bucket(bucketSectorUsage) 27 // Make sure that the number of sectors in the sector usage map and the 28 // number of sectors in the database are the same. 29 if len(sectorUsageMap) != bsu.Stats().KeyN { 30 return errors.New("BucketSectorUsage has the wrong number of sectors recorded") 31 } 32 33 // For every sector in the sector usage map, make sure the database has 34 // a matching sector with the right expiry information. 35 for sectorRoot, expiryHeights := range sectorUsageMap { 36 usageBytes := bsu.Get(smt.sm.sectorID(sectorRoot[:])) 37 if usageBytes == nil { 38 return errors.New("no usage info on known sector") 39 } 40 var usage sectorUsage 41 err := json.Unmarshal(usageBytes, &usage) 42 if err != nil { 43 return err 44 } 45 if len(usage.Expiry) != len(expiryHeights) { 46 return errors.New("usage information mismatch") 47 } 48 for i, expiryHeight := range usage.Expiry { 49 if expiryHeight != expiryHeights[i] { 50 // The correctness could be made not-implementation 51 // dependent by sorting the two arrays before comparing 52 // them, but that was deemed an unneeded step for this 53 // test. 54 return errors.New("usage expiry height mismatch - correctness is implementation dependent") 55 } 56 } 57 } 58 return nil 59 }) 60 } 61 62 // TestStorageFolderUsage is a general integration test which tries all of the 63 // major storage folder operations in various orders, all while adding and 64 // removing sectors to verify that the behavior works as expected. 65 func TestStorageFolderUsage(t *testing.T) { 66 if testing.Short() { 67 t.SkipNow() 68 } 69 t.Parallel() 70 smt, err := newStorageManagerTester("TestStorageFolderUsage") 71 if err != nil { 72 t.Fatal(err) 73 } 74 75 // Start by checking that the initial state of the manager has no storage 76 // added to it. 77 totalStorage, remainingStorage := smt.sm.capacity() 78 if totalStorage != 0 || remainingStorage != 0 { 79 t.Error("initial capacity of manager is not reported at 0 - but no drives have been added!") 80 } 81 82 // Try adding a sector when there are no storage folders. 83 sectorRoot, sectorData, err := createSector() 84 if err != nil { 85 t.Fatal(err) 86 } 87 err = smt.sm.AddSector(sectorRoot, 10, sectorData) 88 if err != errInsufficientStorageForSector { 89 t.Fatal(err) 90 } 91 92 // Add a storage folder, simulating a new drive being connected to the 93 // manager. 94 storageFolderOne := filepath.Join(smt.persistDir, "manager drive 1") 95 // Try using a file size that is too small. Because a filesize check is 96 // quicker than a disk check, the filesize check should come first. 97 err = smt.sm.AddStorageFolder(storageFolderOne, minimumStorageFolderSize-1) 98 if err != errSmallStorageFolder { 99 t.Fatal("expecting errSmallStorageFolder:", err) 100 } 101 // Try a file size that is too large. 102 err = smt.sm.AddStorageFolder(storageFolderOne, maximumStorageFolderSize+1) 103 if err != errLargeStorageFolder { 104 t.Fatal("expecting errLargeStorageFolder:", err) 105 } 106 // Try linking to a storage folder that does not exist. 107 err = smt.sm.AddStorageFolder(storageFolderOne, minimumStorageFolderSize) 108 if err == nil { 109 t.Fatal("should not be able to link to a storage folder which does not exist") 110 } 111 // Try linking to a storage folder that's not a directory. 112 err = ioutil.WriteFile(storageFolderOne, make([]byte, minimumStorageFolderSize), 0700) 113 if err != nil { 114 t.Fatal(err) 115 } 116 err = smt.sm.AddStorageFolder(storageFolderOne, minimumStorageFolderSize) 117 if err != errStorageFolderNotFolder { 118 t.Fatal(err) 119 } 120 // Try linking to a storage folder that is a directory. 121 err = os.Remove(storageFolderOne) 122 if err != nil { 123 t.Fatal(err) 124 } 125 err = os.Mkdir(storageFolderOne, 0700) 126 if err != nil { 127 t.Fatal(err) 128 } 129 err = smt.sm.AddStorageFolder(storageFolderOne, minimumStorageFolderSize) 130 if err != nil { 131 t.Fatal(err) 132 } 133 // Do a probabilistic reset of the manager, to verify that the persistence 134 // structures can reboot without causing issues. 135 err = smt.probabilisticReset() 136 if err != nil { 137 t.Fatal(err) 138 } 139 // Check that the manager has correctly updated the amount of total storage. 140 totalStorage, remainingStorage = smt.sm.capacity() 141 if totalStorage != minimumStorageFolderSize || remainingStorage != minimumStorageFolderSize { 142 t.Error("manager capacity has not been correctly updated after adding a storage folder") 143 t.Error(totalStorage, minimumStorageFolderSize, remainingStorage) 144 } 145 146 // Add a second storage folder. 147 storageFolderTwo := filepath.Join(smt.persistDir, "managerDrive2") 148 err = os.Mkdir(storageFolderTwo, 0700) 149 if err != nil { 150 t.Fatal(err) 151 } 152 err = smt.sm.AddStorageFolder(storageFolderTwo, minimumStorageFolderSize*2) 153 if err != nil { 154 t.Fatal(err) 155 } 156 // Do a probabilistic reset of the manager, to verify that the persistence 157 // structures can reboot without causing issues. 158 err = smt.probabilisticReset() 159 if err != nil { 160 t.Fatal(err) 161 } 162 // Check that the manager has correctly updated the amount of total 163 // storage. 164 totalStorage, remainingStorage = smt.sm.capacity() 165 if totalStorage != minimumStorageFolderSize*3 || remainingStorage != minimumStorageFolderSize*3 { 166 t.Error("manager capacity has not been correctly updated after adding a storage folder") 167 } 168 // Try removing the storage folder using illegal values. 169 err = smt.sm.RemoveStorageFolder(-1, false) 170 if err != errBadStorageFolderIndex { 171 t.Fatal(err) 172 } 173 err = smt.sm.RemoveStorageFolder(2, false) 174 if err != errBadStorageFolderIndex { 175 t.Fatal(err) 176 } 177 178 // Try removing the second storage folder. Before removing the storage 179 // folder, grab the path of the symlink so we can check later that it was 180 // properly removed from the filesystem. 181 symPath := filepath.Join(smt.sm.persistDir, smt.sm.storageFolders[1].uidString()) 182 // Remove the storage folder. 183 err = smt.sm.RemoveStorageFolder(1, false) 184 if err != nil { 185 t.Fatal(err) 186 } 187 // Do a probabilistic reset of the manager, to verify that the persistence 188 // structures can reboot without causing issues. 189 err = smt.probabilisticReset() 190 if err != nil { 191 t.Fatal(err) 192 } 193 // Check that the manager has correctly updated the amount of total 194 // storage. 195 totalStorage, remainingStorage = smt.sm.capacity() 196 if totalStorage != minimumStorageFolderSize || remainingStorage != minimumStorageFolderSize { 197 t.Error("manager capacity has not been correctly updated after adding a storage folder") 198 } 199 _, err = os.Stat(symPath) 200 if err == nil || !os.IsNotExist(err) { 201 t.Error("Does not appear that the sympath was removed from disk:", err) 202 } 203 204 // No sectors added yet, the storage folder statistics should all be clean. 205 for _, sf := range smt.sm.storageFolders { 206 if sf.SuccessfulReads != 0 || sf.SuccessfulWrites != 0 || sf.FailedReads != 0 || sf.FailedWrites != 0 { 207 t.Error("storage folder does not have blank health stats") 208 } 209 } 210 211 // Retry adding the sector, the add should succeed and the amount of 212 // remaining storage should be updated. 213 sectorExpiry := types.BlockHeight(10) 214 err = smt.sm.AddSector(sectorRoot, sectorExpiry, sectorData) 215 if err != nil { 216 t.Fatal(err) 217 } 218 // Check that the capacity has updated to reflected the new sector. 219 totalStorage, remainingStorage = smt.sm.capacity() 220 if totalStorage != minimumStorageFolderSize || remainingStorage != minimumStorageFolderSize-modules.SectorSize { 221 t.Error("manager capacity has not been correctly updated after adding a sector", totalStorage, remainingStorage) 222 } 223 // Check that the sector has been added to the filesystem correctly - the 224 // file should exist in storageFolderOne, and the data in the file should 225 // match the data of the sector. 226 sectorPath := filepath.Join(storageFolderOne, string(smt.sm.sectorID(sectorRoot[:]))) 227 err = func() error { 228 sectorFile, err := os.Open(sectorPath) 229 defer sectorFile.Close() 230 fileInfo, err := sectorFile.Stat() 231 if err != nil { 232 return err 233 } 234 if uint64(fileInfo.Size()) != modules.SectorSize { 235 return errors.New("scanned sector is not the right size") 236 } 237 readSectorData, err := ioutil.ReadAll(sectorFile) 238 if err != nil { 239 return err 240 } 241 if bytes.Compare(readSectorData, sectorData) != 0 { 242 return errors.New("read sector does not match sector data") 243 } 244 return nil 245 }() 246 if err != nil { 247 t.Fatal(err) 248 } 249 // Check that the sector as represented in the database has the correct 250 // height values. 251 err = smt.sm.db.View(func(tx *bolt.Tx) error { 252 bsu := tx.Bucket(bucketSectorUsage) 253 usageBytes := bsu.Get(smt.sm.sectorID(sectorRoot[:])) 254 var usage sectorUsage 255 err := json.Unmarshal(usageBytes, &usage) 256 if err != nil { 257 return err 258 } 259 if len(usage.Expiry) != 1 { 260 return errors.New("wrong usage expiry length in BucketSectorUsage") 261 } 262 if usage.Expiry[0] != 10 { 263 return errors.New("usage expiry for sector is set to the wrong height") 264 } 265 return nil 266 }) 267 if err != nil { 268 t.Fatal(err) 269 } 270 // Check that the disk health stats match the expected values. 271 for _, sf := range smt.sm.storageFolders { 272 if sf.SuccessfulReads != 0 || sf.SuccessfulWrites != 1 || sf.FailedReads != 0 || sf.FailedWrites != 0 { 273 t.Error("storage folder does not have blank health stats") 274 } 275 } 276 277 // Try to resize the storage folder. While resizing the storage folder, try 278 // a bunch of invalid resize calls. 279 err = smt.sm.ResizeStorageFolder(1, minimumStorageFolderSize-1) 280 if err != errBadStorageFolderIndex { 281 t.Error(err) 282 } 283 err = smt.sm.ResizeStorageFolder(-1, minimumStorageFolderSize-1) 284 if err != errBadStorageFolderIndex { 285 t.Error(err) 286 } 287 err = smt.sm.ResizeStorageFolder(0, minimumStorageFolderSize-1) 288 if err != errSmallStorageFolder { 289 t.Error(err) 290 } 291 err = smt.sm.ResizeStorageFolder(0, maximumStorageFolderSize+1) 292 if err != errLargeStorageFolder { 293 t.Error(err) 294 } 295 err = smt.sm.ResizeStorageFolder(0, minimumStorageFolderSize*10) 296 if err != nil { 297 t.Fatal(err) 298 } 299 err = smt.sm.ResizeStorageFolder(0, minimumStorageFolderSize*10) 300 if err != errNoResize { 301 t.Fatal(err) 302 } 303 // Do a probabilistic reset of the manager, to verify that the persistence 304 // structures can reboot without causing issues. 305 err = smt.probabilisticReset() 306 if err != nil { 307 t.Fatal(err) 308 } 309 // Manager should be able to support having uneven storage sizes. 310 oddStorageSize := (minimumStorageFolderSize) + modules.SectorSize*3 + 3 311 err = smt.sm.ResizeStorageFolder(0, oddStorageSize) 312 if err != nil { 313 t.Fatal(err) 314 } 315 316 // Create a sector list, containing all sectors (including repeats) and the 317 // heights at which they expire. This sector list will be updated as 318 // sectors are added and removed. 319 sectorUsageMap := make(map[crypto.Hash][]types.BlockHeight) 320 sectorUsageMap[sectorRoot] = []types.BlockHeight{sectorExpiry} 321 // Sanity check - manager should not have any sectors in it. 322 totalStorage, remainingStorage = smt.sm.capacity() 323 if totalStorage != remainingStorage+modules.SectorSize { 324 t.Fatal("manager is not empty at the moment of creating the in-memory sector usage map") 325 } 326 // Verify that the initial sector usage map was created correctly. 327 err = smt.sectorUsageCheck(sectorUsageMap) 328 if err != nil { 329 t.Fatal(err) 330 } 331 332 // Fill the storage folder above the minimum size, then try to shrink it to 333 // the minimum size. 334 for i := uint64(0); i <= minimumStorageFolderSize/modules.SectorSize; i++ { 335 sectorRoot, sectorData, err := createSector() 336 if err != nil { 337 t.Fatal(err) 338 } 339 err = smt.sm.AddSector(sectorRoot, 86+types.BlockHeight(i), sectorData) 340 if err != nil { 341 t.Fatal(err) 342 } 343 // Do a probabilistic reset of the manager, to verify that the persistence 344 // structures can reboot without causing issues. 345 err = smt.probabilisticReset() 346 if err != nil { 347 t.Fatal(err) 348 } 349 // Now that there is a sector usage map, it must be kept consistent 350 // with the sector usage in the manager. 351 sectorUsageMap[sectorRoot] = []types.BlockHeight{86 + types.BlockHeight(i)} 352 } 353 oldSize := smt.sm.storageFolders[0].Size 354 err = smt.sm.ResizeStorageFolder(0, minimumStorageFolderSize) 355 if err != errIncompleteOffload { 356 t.Fatal(err) 357 } 358 size := smt.sm.storageFolders[0].Size 359 sizeRemaining := smt.sm.storageFolders[0].SizeRemaining 360 if size >= oldSize || sizeRemaining > 0 { 361 t.Fatal("manager did not correctly update the size remaining after an incomplete shrink") 362 } 363 364 // Try adding another sector, there should not be enough room. 365 sr, sd, err := createSector() 366 if err != nil { 367 t.Fatal(err) 368 } 369 err = smt.sm.AddSector(sr, 186, sd) 370 if err != errInsufficientStorageForSector { 371 t.Fatal(err) 372 } 373 374 // Add a second folder, and add a sector to that folder. There should be 375 // enough space remaining in the first folder for the removal to be 376 // successful. 377 err = smt.sm.AddStorageFolder(storageFolderTwo, minimumStorageFolderSize*2) 378 if err != nil { 379 t.Fatal(err) 380 } 381 // Do a probabilistic reset of the manager, to verify that the persistence 382 // structures can reboot without causing issues. 383 err = smt.probabilisticReset() 384 if err != nil { 385 t.Fatal(err) 386 } 387 sectorRoot, sectorData, err = createSector() 388 if err != nil { 389 t.Fatal(err) 390 } 391 err = smt.sm.AddSector(sectorRoot, 81, sectorData) 392 if err != nil { 393 t.Fatal(err) 394 } 395 sectorUsageMap[sectorRoot] = []types.BlockHeight{81} 396 // Check that the sector ended up in the right storage folder - because the 397 // second storage folder is the least full, the sector should end up there. 398 folderTwoUsage := smt.sm.storageFolders[1].Size - smt.sm.storageFolders[1].SizeRemaining 399 if folderTwoUsage != modules.SectorSize { 400 t.Error("sector did not appear to land in the right storage folder") 401 } 402 // Check the filesystem. The folder for storage folder 1 should have 10 403 // files, and the folder for storage folder 2 should have 1 file. 404 infos, err := ioutil.ReadDir(storageFolderOne) 405 if err != nil { 406 t.Fatal(err) 407 } 408 if len(infos) != 10 { 409 t.Fatal("storage folder one should have 10 sectors in it") 410 } 411 infos, err = ioutil.ReadDir(storageFolderTwo) 412 if err != nil { 413 t.Fatal(err) 414 } 415 if len(infos) != 1 { 416 t.Fatal("storage folder two should have 1 sector in it") 417 } 418 419 // The first storage folder has more sectors than the minimum allowed 420 // amount. Reduce the size of the first storage folder to minimum, which 421 // should be accepted but will result in sectors being transferred to the 422 // second storage folder. 423 totalStorage, remainingStorage = smt.sm.capacity() 424 prevStorage := totalStorage 425 usedStorage := totalStorage - remainingStorage 426 err = smt.sm.ResizeStorageFolder(0, minimumStorageFolderSize) 427 if err != nil { 428 t.Fatal(err) 429 } 430 totalStorage, remainingStorage = smt.sm.capacity() 431 if usedStorage != totalStorage-remainingStorage { 432 t.Error("the used storage value adjusted after removing a storage folder", usedStorage, totalStorage-remainingStorage) 433 } 434 if totalStorage >= prevStorage { 435 t.Error("total storage was not adjusted correctly after removing a storage folder") 436 } 437 // Check the filesystem. 438 infos, err = ioutil.ReadDir(storageFolderOne) 439 if err != nil { 440 t.Fatal(err) 441 } 442 if len(infos) != 8 { 443 t.Fatal("wrong number of sectors in storage folder one") 444 } 445 infos, err = ioutil.ReadDir(storageFolderTwo) 446 if len(infos) != 3 { 447 t.Fatal("wrong number of sectors in storage folder two") 448 } 449 450 // Remove the first storage folder, which should result in all of the 451 // sectors being moved to the second storage folder. Note that 452 // storageFolderTwo now has an index of '0'. 453 totalStorage, remainingStorage = smt.sm.capacity() 454 prevStorage = totalStorage 455 usedStorage = totalStorage - remainingStorage 456 symPath = filepath.Join(smt.sm.persistDir, smt.sm.storageFolders[0].uidString()) 457 err = smt.sm.RemoveStorageFolder(0, false) 458 if err != nil { 459 t.Fatal(err) 460 } 461 totalStorage, remainingStorage = smt.sm.capacity() 462 if usedStorage != totalStorage-remainingStorage { 463 t.Error("the used storage value adjusted after removing a storage folder", usedStorage, totalStorage-remainingStorage) 464 } 465 if totalStorage == prevStorage { 466 t.Error("total storage was not adjusted after removing a storage folder") 467 } 468 // Check that the filesystem seems correct. 469 infos, err = ioutil.ReadDir(storageFolderTwo) 470 if err != nil { 471 t.Fatal(err) 472 } 473 if len(infos) != 11 { 474 t.Fatal("wrong number of sectors in folder") 475 } 476 _, err = os.Stat(symPath) 477 if !os.IsNotExist(err) { 478 t.Fatal("the sym link to the deleted storage folder should no longer exist") 479 } 480 481 // Add the first storage folder, resize the second storage folder back down 482 // to minimum. Note that storageFolderOne now has an index of '1', and 483 // storageFolderTwo now has an index of '0'. 484 err = smt.sm.AddStorageFolder(storageFolderOne, minimumStorageFolderSize) 485 if err != nil { 486 t.Fatal(err) 487 } 488 err = smt.sm.ResizeStorageFolder(0, minimumStorageFolderSize) 489 if err != nil { 490 t.Fatal(err) 491 } 492 // Do a probabilistic reset of the manager, to verify that the persistence 493 // structures can reboot without causing issues. 494 err = smt.probabilisticReset() 495 if err != nil { 496 t.Fatal(err) 497 } 498 // Check the filesystem. 499 infos, err = ioutil.ReadDir(storageFolderTwo) 500 if err != nil { 501 t.Fatal(err) 502 } 503 if len(infos) != 8 { 504 t.Fatal("wrong number of sectors") 505 } 506 infos, err = ioutil.ReadDir(storageFolderOne) 507 if err != nil { 508 t.Fatal(err) 509 } 510 if len(infos) != 3 { 511 t.Fatal("wrong number of sectors") 512 } 513 514 // Add a bunch of sectors and repeat sectors at multiple colliding heights. 515 // Start by resizing the first storage folder so that there is enough room 516 // for the new sectors. 517 err = smt.sm.ResizeStorageFolder(0, minimumStorageFolderSize*3) 518 if err != nil { 519 t.Fatal(err) 520 } 521 for i := types.BlockHeight(0); i < 10; i++ { 522 // Add 10 unique sectors to the map. 523 sectorRoot, sectorData, err := createSector() 524 if err != nil { 525 t.Fatal(err) 526 } 527 for j := types.BlockHeight(0); j < 5; j++ { 528 // Add the unique sectors at multiple heights, creating virtual 529 // sectors. 530 for k := types.BlockHeight(0); k < 4; k++ { 531 // Add in an extra loop so that height collisions can be 532 // created such that the collisions happen out of order. 533 // Sectors are added at height 10+j+k, which means that there 534 // will be many collisions for each height, but the collisions 535 // are not happening in sorted order. The manager is not 536 // expected to do sorting, but should also not be confused by a 537 // random order. 538 err = smt.sm.AddSector(sectorRoot, 10+j+k, sectorData) 539 if err != nil { 540 t.Fatal(err) 541 } 542 543 // Add the sector to the sectorUsageMap, so it can be deleted 544 // later. 545 expiryList, exists := sectorUsageMap[sectorRoot] 546 if exists { 547 sectorUsageMap[sectorRoot] = append(expiryList, 10+j+k) 548 } else { 549 sectorUsageMap[sectorRoot] = []types.BlockHeight{10 + j + k} 550 } 551 } 552 // Do a probabilistic reset of the manager, to verify that the 553 // persistence structures can reboot without causing issues. 554 err = smt.probabilisticReset() 555 if err != nil { 556 t.Fatal(err) 557 } 558 } 559 } 560 // Check that the amount of storage in use represents 10 sectors, and not 561 // more - all the others are repeats and shouldn't be counted. 562 totalStorage, remainingStorage = smt.sm.capacity() 563 if totalStorage != minimumStorageFolderSize*4 || remainingStorage != minimumStorageFolderSize*4-modules.SectorSize*21 { 564 t.Fatal("Manager not reporting expected storage capacity:", totalStorage, remainingStorage, minimumStorageFolderSize*4, minimumStorageFolderSize*4-modules.SectorSize*21) 565 } 566 // Check that the internal sector usage database of the manager has been 567 // updated correctly. 568 err = smt.sectorUsageCheck(sectorUsageMap) 569 if err != nil { 570 t.Fatal(err) 571 } 572 // Check the filesystem. 573 infos, err = ioutil.ReadDir(storageFolderTwo) 574 if err != nil { 575 t.Fatal(err) 576 } 577 if len(infos) != 16 { 578 t.Fatal("there should be 16 sectors in storage folder two") 579 } 580 infos, err = ioutil.ReadDir(storageFolderOne) 581 if err != nil { 582 t.Fatal(err) 583 } 584 if len(infos) != 5 { 585 t.Fatal("there should be 5 sectors in storage folder one") 586 } 587 // Try removing a non-repeat sector. 588 expiryHeights, exists := sectorUsageMap[sectorRoot] 589 if !exists || len(expiryHeights) != 1 { 590 t.Fatal("sector map doesn't match testing assumptions") 591 } 592 // Try some illegal sector removal operations before trying a legal one. 593 err = smt.sm.RemoveSector(sectorRoot, sectorExpiry+50e6) 594 if err != errSectorNotFound { 595 t.Fatal("wrong error when removing illegal sector:", err) 596 } 597 alteredRoot := sectorRoot 598 alteredRoot[0]++ 599 err = smt.sm.RemoveSector(alteredRoot, 81) 600 if err != errSectorNotFound { 601 t.Fatal("wrong error when removing illegal sector:", err) 602 } 603 // Now try the legal sector removal. 604 sectorPath = filepath.Join(storageFolderOne, string(smt.sm.sectorID(sectorRoot[:]))) 605 err = smt.sm.RemoveSector(sectorRoot, 81) 606 if err != nil { 607 t.Fatal(err) 608 } 609 // Do a probabilistic reset of the manager, to verify that the persistence 610 // structures can reboot without causing issues. 611 err = smt.probabilisticReset() 612 if err != nil { 613 t.Fatal(err) 614 } 615 // Update the sector usage map to reflect the departure of a sector. 616 delete(sectorUsageMap, sectorRoot) 617 // Check that the new capacity is being reported correctly. 618 totalStorage, remainingStorage = smt.sm.capacity() 619 if totalStorage != minimumStorageFolderSize*4 || remainingStorage != minimumStorageFolderSize*4-modules.SectorSize*20 { 620 t.Fatal("Manager not reporting expected storage capacity:") 621 } 622 // Run a sector usage check to make sure the manager is properly handling 623 // the usage information when deleting a sector. 624 err = smt.sectorUsageCheck(sectorUsageMap) 625 if err != nil { 626 t.Fatal(err) 627 } 628 // Check that the sector on-disk has been deleted. 629 _, err = os.Stat(sectorPath) 630 if !os.IsNotExist(err) { 631 t.Fatal(err) 632 } 633 // Check that the total number of sectors seen on disk is 20. 634 infos, err = ioutil.ReadDir(storageFolderOne) 635 if err != nil { 636 t.Fatal(err) 637 } 638 infos2, err := ioutil.ReadDir(storageFolderTwo) 639 if err != nil { 640 t.Fatal(err) 641 } 642 if len(infos)+len(infos2) != 20 { 643 t.Fatal("there should be 20 sectors total on disk at this point") 644 } 645 646 // Remove two of the duplicated sectors, one copy at a time, to see that 647 // the database is still updating correctly. 648 var secondIteration bool 649 var targetedRoots []crypto.Hash 650 for sectorRoot, expiryHeights := range sectorUsageMap { 651 if len(expiryHeights) < 2 { 652 continue 653 } 654 targetedRoots = append(targetedRoots, sectorRoot) 655 // Break on the second iteration. 656 if secondIteration { 657 break 658 } 659 secondIteration = true 660 } 661 // Remove, one piece at a time, the two targeted sectors. 662 for i, root := range targetedRoots { 663 // Grab the initial remaining storage, to make sure that it's not being 664 // changed when one instance of a repeated sector is removed. 665 _, initialRemainingStorage := smt.sm.capacity() 666 667 // Remove the heights one at a time. 668 expiryHeights := sectorUsageMap[root] 669 for len(expiryHeights) > 0 { 670 // Check that the remaining storage is still the same. 671 _, remainingStorage := smt.sm.capacity() 672 if remainingStorage != initialRemainingStorage { 673 t.Fatal("manager is changing the amount of storage remaining when removing virtual sectors") 674 } 675 676 // Try to remove the sector using a wildcard expiry height. 677 err = smt.sm.RemoveSector(root, expiryHeights[0]+548e6) 678 if err != errSectorNotFound { 679 t.Fatal(err) 680 } 681 682 // Remove the sector from the manager. 683 err = smt.sm.RemoveSector(root, expiryHeights[0]) 684 if err != nil { 685 t.Fatal(err) 686 } 687 688 // Check that the filesystem is housing the correct number of 689 // sectors. 690 infos, err = ioutil.ReadDir(storageFolderOne) 691 if err != nil { 692 t.Fatal(err) 693 } 694 infos2, err = ioutil.ReadDir(storageFolderTwo) 695 if err != nil { 696 t.Fatal(err) 697 } 698 bonus := 0 699 if len(expiryHeights) == 1 { 700 // If this is the last expiry height, the sector is no longer 701 // viritual and is being removed for real, so we need to 702 // subtract it from the expected total number of sectors. 703 bonus++ 704 } 705 if len(infos)+len(infos2) != 20-i-bonus { 706 t.Fatal("sector count is incorrect while managing virtual sectors") 707 } 708 709 // Update the sector map to reflect the removed sector. 710 if len(expiryHeights) > 1 { 711 expiryHeights = expiryHeights[1:] 712 sectorUsageMap[root] = expiryHeights 713 } else { 714 expiryHeights = nil 715 delete(sectorUsageMap, root) 716 } 717 err = smt.sectorUsageCheck(sectorUsageMap) 718 if err != nil { 719 t.Fatal(err) 720 } 721 } 722 // Do a probabilistic reset of the manager, to verify that the 723 // persistence structures can reboot without causing issues. 724 err = smt.probabilisticReset() 725 if err != nil { 726 t.Fatal(err) 727 } 728 // Check that the remaining storage is still the same. 729 _, remainingStorage := smt.sm.capacity() 730 if remainingStorage != initialRemainingStorage+modules.SectorSize { 731 t.Fatal("manager incorrectly updated remaining space when deleting the final height for a sector") 732 } 733 } 734 735 // Add a third storage folder. 736 prevTotalStorage, prevRemainingStorage := smt.sm.capacity() 737 storageFolderThree := filepath.Join(smt.persistDir, "hd3") 738 err = os.Mkdir(storageFolderThree, 0700) 739 if err != nil { 740 t.Fatal(err) 741 } 742 err = smt.sm.AddStorageFolder(storageFolderThree, minimumStorageFolderSize*2) 743 if err != nil { 744 t.Fatal(err) 745 } 746 // Check that the total storage and remaining storage updated correctly. 747 totalStorage, remainingStorage = smt.sm.capacity() 748 if totalStorage != prevTotalStorage+minimumStorageFolderSize*2 || remainingStorage != prevRemainingStorage+minimumStorageFolderSize*2 { 749 t.Fatal("storage folder sizes are not being updated correctly when new storage folders are added") 750 } 751 752 // Add sectors until the storage folders have no more capacity. 753 _, remainingStorage = smt.sm.capacity() 754 remainingSectors := remainingStorage / modules.SectorSize 755 for i := uint64(0); i < remainingSectors; i++ { 756 sectorRoot, sectorData, err := createSector() 757 if err != nil { 758 t.Fatal(err) 759 } 760 err = smt.sm.AddSector(sectorRoot, 36, sectorData) 761 if err != nil { 762 t.Fatal(err) 763 } 764 sectorUsageMap[sectorRoot] = []types.BlockHeight{36} 765 } 766 // Add another sector, which will not fit in the manager. 767 sectorRoot, sectorData, err = createSector() 768 if err != nil { 769 t.Fatal(err) 770 } 771 err = smt.sm.AddSector(sectorRoot, 36, sectorData) 772 if err != errInsufficientStorageForSector { 773 t.Fatal(err) 774 } 775 // Do a probabilistic reset of the manager, to verify that the persistence 776 // structures can reboot without causing issues. 777 err = smt.probabilisticReset() 778 if err != nil { 779 t.Fatal(err) 780 } 781 _, remainingStorage = smt.sm.capacity() 782 if remainingStorage >= modules.SectorSize { 783 t.Error("remaining storage is reporting incorrect result - should report that there is not enough room for another sector") 784 } 785 err = smt.sectorUsageCheck(sectorUsageMap) 786 if err != nil { 787 t.Fatal(err) 788 } 789 // Check the filesystem. 790 infos, err = ioutil.ReadDir(storageFolderOne) 791 if err != nil { 792 t.Fatal(err) 793 } 794 if len(infos) != 8 { 795 t.Fatal("expecting 8 sectors in storage folder one") 796 } 797 infos, err = ioutil.ReadDir(storageFolderTwo) 798 if err != nil { 799 t.Fatal(err) 800 } 801 if len(infos) != 24 { 802 t.Fatal("expecting 24 sectors in storage folder two") 803 } 804 infos, err = ioutil.ReadDir(storageFolderThree) 805 if err != nil { 806 t.Fatal(err) 807 } 808 if len(infos) != 16 { 809 t.Fatal("expecting 16 sectors in storage folder three") 810 } 811 812 // Do some resizing, to cause sectors to be moved around. Every storage 813 // folder should have sectors that get moved off of it. 814 err = smt.sm.ResizeStorageFolder(1, minimumStorageFolderSize*6) 815 if err != nil { 816 t.Fatal(err) 817 } 818 err = smt.sm.ResizeStorageFolder(0, minimumStorageFolderSize) 819 if err != nil { 820 t.Fatal(err) 821 } 822 err = smt.sm.ResizeStorageFolder(2, minimumStorageFolderSize) 823 if err != nil { 824 t.Fatal(err) 825 } 826 err = smt.sm.ResizeStorageFolder(0, minimumStorageFolderSize*6) 827 if err != nil { 828 t.Fatal(err) 829 } 830 err = smt.sm.ResizeStorageFolder(1, minimumStorageFolderSize) 831 if err != nil { 832 t.Fatal(err) 833 } 834 // Check that all storage folders are reporting successful reads and 835 // writes, with no failures. 836 for _, sf := range smt.sm.storageFolders { 837 if sf.SuccessfulWrites <= 0 || sf.SuccessfulReads <= 0 || sf.FailedWrites > 0 || sf.FailedReads > 0 { 838 t.Error("disk stats aren't making sense") 839 } 840 } 841 842 // Remove all of the sectors. 843 i := 0 844 for sectorRoot, expiryHeights := range sectorUsageMap { 845 // Grab the initial remaining storage, to make sure that it's not being 846 // changed when one instance of a repeated sector is removed. 847 _, initialRemainingStorage := smt.sm.capacity() 848 849 // Remove the heights one at a time. 850 for j := range expiryHeights { 851 // Check that the remaining storage is still the same. 852 _, remainingStorage := smt.sm.capacity() 853 if remainingStorage != initialRemainingStorage { 854 t.Fatal("manager is changing the amount of storage remaining when removing virtual sectors") 855 } 856 857 // Remove the sector from the manager. 858 err = smt.sm.RemoveSector(sectorRoot, expiryHeights[j]) 859 if err != nil { 860 t.Fatal(err) 861 } 862 863 // Check that the filesystem is housing the correct number of 864 // sectors. 865 infos, err := ioutil.ReadDir(storageFolderOne) 866 if err != nil { 867 t.Fatal(err) 868 } 869 infos2, err := ioutil.ReadDir(storageFolderTwo) 870 if err != nil { 871 t.Fatal(err) 872 } 873 infos3, err := ioutil.ReadDir(storageFolderThree) 874 if err != nil { 875 t.Fatal(err) 876 } 877 bonus := 0 878 if j == len(expiryHeights)-1 { 879 // If this is the last expiry height, the sector is no longer 880 // viritual and is being removed for real, so we need to 881 // subtract it from the expected total number of sectors. 882 bonus++ 883 } 884 if len(infos)+len(infos2)+len(infos3) != 48-i-bonus { 885 t.Error(len(infos)+len(infos2)+len(infos3), i, bonus) 886 t.Fatal("sector count is incorrect while managing virtual sectors") 887 } 888 } 889 // Do a probabilistic reset of the manager, to verify that the 890 // persistence structures can reboot without causing issues. 891 err = smt.probabilisticReset() 892 if err != nil { 893 t.Fatal(err) 894 } 895 // Check that the remaining storage is still the same. 896 _, remainingStorage := smt.sm.capacity() 897 if remainingStorage != initialRemainingStorage+modules.SectorSize { 898 t.Fatal("manager incorrectly updated remaining space when deleting the final height for a sector") 899 } 900 i++ 901 } 902 // Check that all storage folders have successful writes, and no failed 903 // reads or writes. 904 for _, sf := range smt.sm.storageFolders { 905 if sf.SuccessfulWrites <= 0 || sf.SuccessfulReads <= 0 || sf.FailedWrites > 0 || sf.FailedReads > 0 { 906 t.Error("disk stats aren't making sense") 907 } 908 } 909 910 // Remove all of the storage folders. 911 for i := 0; i < 3; i++ { 912 err = smt.sm.RemoveStorageFolder(0, false) 913 if err != nil { 914 t.Fatal(err) 915 } 916 } 917 // Check the filesystem, there should be 3 files in the manager folder 918 // (storagemanager.db, storagemanager.json, storagemanager.log). 919 infos, err = ioutil.ReadDir(smt.sm.persistDir) 920 if err != nil { 921 t.Fatal(err) 922 } 923 if len(infos) != 3 { 924 t.Error("unexpected number of files in the manager directory") 925 } 926 }