gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/renter/persist.go (about) 1 package renter 2 3 import ( 4 "os" 5 "path/filepath" 6 7 "gitlab.com/NebulousLabs/errors" 8 9 "gitlab.com/SiaPrime/SiaPrime/modules" 10 "gitlab.com/SiaPrime/SiaPrime/modules/renter/siadir" 11 "gitlab.com/SiaPrime/SiaPrime/modules/renter/siafile" 12 "gitlab.com/SiaPrime/SiaPrime/persist" 13 "gitlab.com/SiaPrime/SiaPrime/types" 14 "gitlab.com/SiaPrime/writeaheadlog" 15 ) 16 17 const ( 18 logFile = modules.RenterDir + ".log" 19 // PersistFilename is the filename to be used when persisting renter 20 // information to a JSON file 21 PersistFilename = "renter.json" 22 // SiaDirMetadata is the name of the metadata file for the sia directory 23 SiaDirMetadata = ".siadir" 24 // walFile is the filename of the renter's writeaheadlog's file. 25 walFile = modules.RenterDir + ".wal" 26 // repairLoopFilename is the filename to be used when persisting bubble 27 // updates that are called from the repair loop 28 repairLoopFilename = "repairloop.json" 29 ) 30 31 var ( 32 //ErrBadFile is an error when a file does not qualify as .sia file 33 ErrBadFile = errors.New("not a .sia file") 34 // ErrIncompatible is an error when file is not compatible with current 35 // version 36 ErrIncompatible = errors.New("file is not compatible with current version") 37 // ErrNoNicknames is an error when no nickname is given 38 ErrNoNicknames = errors.New("at least one nickname must be supplied") 39 // ErrNonShareSuffix is an error when the suffix of a file does not match 40 // the defined share extension 41 ErrNonShareSuffix = errors.New("suffix of file must be " + modules.SiaFileExtension) 42 43 settingsMetadata = persist.Metadata{ 44 Header: "Renter Persistence", 45 Version: persistVersion, 46 } 47 48 shareHeader = [15]byte{'S', 'i', 'a', ' ', 'S', 'h', 'a', 'r', 'e', 'd', ' ', 'F', 'i', 'l', 'e'} 49 shareVersion = "0.4" 50 51 // Persist Version Numbers 52 persistVersion040 = "0.4" 53 persistVersion133 = "1.3.3" 54 persistVersion140 = "1.4.0" 55 ) 56 57 type ( 58 // persist contains all of the persistent renter data. 59 persistence struct { 60 MaxDownloadSpeed int64 61 MaxUploadSpeed int64 62 UploadedBackups []modules.UploadedBackup 63 SyncedContracts []types.FileContractID 64 } 65 ) 66 67 // saveSync stores the current renter data to disk and then syncs to disk. 68 func (r *Renter) saveSync() error { 69 return persist.SaveJSON(settingsMetadata, r.persist, filepath.Join(r.persistDir, PersistFilename)) 70 } 71 72 // managedLoadSettings fetches the saved renter data from disk. 73 func (r *Renter) managedLoadSettings() error { 74 r.persist = persistence{} 75 err := persist.LoadJSON(settingsMetadata, &r.persist, filepath.Join(r.persistDir, PersistFilename)) 76 if os.IsNotExist(err) { 77 // No persistence yet, set the defaults and continue. 78 r.persist.MaxDownloadSpeed = DefaultMaxDownloadSpeed 79 r.persist.MaxUploadSpeed = DefaultMaxUploadSpeed 80 id := r.mu.Lock() 81 err = r.saveSync() 82 r.mu.Unlock(id) 83 if err != nil { 84 return err 85 } 86 } else if err == persist.ErrBadVersion { 87 // Outdated version, try the 040 to 133 upgrade. 88 err = convertPersistVersionFrom040To133(filepath.Join(r.persistDir, PersistFilename)) 89 if err != nil { 90 r.log.Println("WARNING: 040 to 133 renter upgrade failed, trying 133 to 140 next", err) 91 } 92 // Then upgrade from 133 to 140. 93 oldContracts := r.hostContractor.OldContracts() 94 err = r.convertPersistVersionFrom133To140(filepath.Join(r.persistDir, PersistFilename), oldContracts) 95 if err != nil { 96 r.log.Println("WARNING: 133 to 140 renter upgrade failed", err) 97 // Nothing left to try. 98 return err 99 } 100 r.log.Println("Renter upgrade successful") 101 // Re-load the settings now that the file has been upgraded. 102 return r.managedLoadSettings() 103 } else if err != nil { 104 return err 105 } 106 107 // Set the bandwidth limits on the contractor, which was already initialized 108 // without bandwidth limits. 109 return r.setBandwidthLimits(r.persist.MaxDownloadSpeed, r.persist.MaxUploadSpeed) 110 } 111 112 // managedInitPersist handles all of the persistence initialization, such as creating 113 // the persistence directory and starting the logger. 114 func (r *Renter) managedInitPersist() error { 115 // Create the persist and files directories if they do not yet exist. 116 // 117 // Note: the os package needs to be used here instead of the renter's 118 // CreateDir method because the staticDirSet has not been initialized yet. 119 // The directory is needed before the staticDirSet can be initialized 120 // because the wal needs the directory to be created and the staticDirSet 121 // needs the wal. 122 err := os.MkdirAll(r.staticFilesDir, 0700) 123 if err != nil { 124 return err 125 } 126 err = os.MkdirAll(r.staticBackupsDir, 0700) 127 if err != nil { 128 return err 129 } 130 131 // Initialize the logger. 132 r.log, err = persist.NewFileLogger(filepath.Join(r.persistDir, logFile)) 133 if err != nil { 134 return err 135 } 136 r.log.Debugln("Renter log started.") 137 if err := r.tg.AfterStop(r.log.Close); err != nil { 138 return err 139 } 140 141 // Initialize the writeaheadlog. 142 options := writeaheadlog.Options{ 143 StaticLog: r.log, 144 Path: filepath.Join(r.persistDir, walFile), 145 } 146 txns, wal, err := writeaheadlog.NewWithOptions(options) 147 if err != nil { 148 return err 149 } 150 if err := r.tg.AfterStop(wal.Close); err != nil { 151 return err 152 } 153 154 // Apply unapplied wal txns before loading the persistence structure to 155 // avoid loading potentially corrupted files. 156 if len(txns) > 0 { 157 r.log.Println("Wal initalized", len(txns), "transactions to apply") 158 } 159 for _, txn := range txns { 160 applyTxn := true 161 r.log.Println("applying transaction with", len(txn.Updates), "updates") 162 for _, update := range txn.Updates { 163 if siafile.IsSiaFileUpdate(update) { 164 r.log.Println("Applying a siafile update:", update.Name) 165 if err := siafile.ApplyUpdates(update); err != nil { 166 return errors.AddContext(err, "failed to apply SiaFile update") 167 } 168 } else if siadir.IsSiaDirUpdate(update) { 169 r.log.Println("Applying a siadir update:", update.Name) 170 if err := siadir.ApplyUpdates(update); err != nil { 171 return errors.AddContext(err, "failed to apply SiaDir update") 172 } 173 } else { 174 r.log.Println("wal update not applied, marking transaction as not applied") 175 applyTxn = false 176 } 177 } 178 if applyTxn { 179 if err := txn.SignalUpdatesApplied(); err != nil { 180 return err 181 } 182 } 183 } 184 185 // Initialize the wal, staticFileSet and the staticDirSet. With the 186 // staticDirSet finish the initialization of the files directory 187 r.wal = wal 188 r.staticFileSet = siafile.NewSiaFileSet(r.staticFilesDir, wal) 189 r.staticDirSet = siadir.NewSiaDirSet(r.staticFilesDir, wal) 190 r.staticBackupFileSet = siafile.NewSiaFileSet(r.staticBackupsDir, wal) 191 r.staticBackupDirSet = siadir.NewSiaDirSet(r.staticBackupsDir, wal) 192 if err := r.staticDirSet.InitRootDir(); err != nil { 193 return err 194 } 195 // Load the prior persistence structures. 196 return r.managedLoadSettings() 197 }