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  }