gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/host/contractmanager/storagefoldershrink.go (about) 1 package contractmanager 2 3 import ( 4 "sync/atomic" 5 6 "gitlab.com/SiaPrime/SiaPrime/modules" 7 ) 8 9 type ( 10 // storageFolderReduction dictates a completed storage folder reduction to 11 // the WAL. 12 storageFolderReduction struct { 13 Index uint16 14 NewSectorCount uint32 15 } 16 ) 17 18 // commitStorageFolderReduction commits a storage folder reduction to the state 19 // and filesystem. 20 func (wal *writeAheadLog) commitStorageFolderReduction(sfr storageFolderReduction) { 21 sf, exists := wal.cm.storageFolders[sfr.Index] 22 if !exists { 23 wal.cm.log.Critical("ERROR: storage folder reduction established for a storage folder that does not exist") 24 return 25 } 26 if atomic.LoadUint64(&sf.atomicUnavailable) == 1 { 27 // Cannot complete the storage folder reduction - storage folder is not 28 // available. 29 return 30 } 31 32 // Shrink the sector usage, but only if the sector usage is not already 33 // smaller. 34 if uint32(len(sf.usage)) > sfr.NewSectorCount/storageFolderGranularity { 35 // Unset the usage in all bits 36 for i := sfr.NewSectorCount; i < uint32(len(sf.usage))*storageFolderGranularity; i++ { 37 sf.clearUsage(i) 38 } 39 // Truncate the usage field. 40 sf.usage = sf.usage[:sfr.NewSectorCount/storageFolderGranularity] 41 } 42 43 // Truncate the storage folder. 44 err := sf.metadataFile.Truncate(int64(sfr.NewSectorCount * sectorMetadataDiskSize)) 45 if err != nil { 46 wal.cm.log.Printf("Error: unable to truncate metadata file as storage folder %v is resized\n", sf.path) 47 } 48 err = sf.sectorFile.Truncate(int64(modules.SectorSize * uint64(sfr.NewSectorCount))) 49 if err != nil { 50 wal.cm.log.Printf("Error: unable to truncate sector file as storage folder %v is resized\n", sf.path) 51 } 52 } 53 54 // shrinkStoragefolder will truncate a storage folder, moving all of the 55 // sectors in the truncated space to new storage folders. 56 func (wal *writeAheadLog) shrinkStorageFolder(index uint16, newSectorCount uint32, force bool) error { 57 // Retrieve the specified storage folder. 58 wal.mu.Lock() 59 sf, exists := wal.cm.storageFolders[index] 60 wal.mu.Unlock() 61 if !exists { 62 return errStorageFolderNotFound 63 } 64 if atomic.LoadUint64(&sf.atomicUnavailable) == 1 { 65 // TODO: Better error. 66 return errStorageFolderNotFound 67 } 68 69 // Lock the storage folder for the duration of the operation. 70 sf.mu.Lock() 71 defer sf.mu.Unlock() 72 73 // Clear out the sectors in the storage folder. 74 _, err := wal.managedEmptyStorageFolder(index, newSectorCount) 75 if err != nil && !force { 76 return err 77 } 78 79 // Wait for a synchronize to confirm that all of the moves have succeeded 80 // in full. 81 wal.mu.Lock() 82 syncChan := wal.syncChan 83 wal.mu.Unlock() 84 <-syncChan 85 86 // Allow unclean shutdown to be simulated by returning before the state 87 // change gets committed. 88 if wal.cm.dependencies.Disrupt("incompleteShrinkStorageFolder") { 89 return nil 90 } 91 92 // Submit a storage folder truncation to the WAL and wait until the update 93 // is synced. 94 wal.mu.Lock() 95 wal.appendChange(stateChange{ 96 StorageFolderReductions: []storageFolderReduction{{ 97 Index: index, 98 NewSectorCount: newSectorCount, 99 }}, 100 }) 101 syncChan = wal.syncChan 102 wal.mu.Unlock() 103 104 // Wait until the shrink action has been synchronized. 105 <-syncChan 106 return nil 107 }