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