github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/host/storagemanager/storagemanager.go (about)

     1  // package storagemanager implements a storage manager for the host on Sia. The
     2  // storage manager can add sectors, remove sectors, and manage how sectors are
     3  // distributed between a number of storage folders.
     4  package storagemanager
     5  
     6  // TODO: The documentation still talks like this code is a part of the host.
     7  
     8  import (
     9  	"errors"
    10  	"path/filepath"
    11  	"sync"
    12  
    13  	"github.com/NebulousLabs/Sia/crypto"
    14  	"github.com/NebulousLabs/Sia/persist"
    15  )
    16  
    17  const (
    18  	// Names of the various persist files in the storage manager.
    19  	dbFilename   = "storagemanager.db"
    20  	logFile      = "storagemanager.log"
    21  	settingsFile = "storagemanager.json"
    22  )
    23  
    24  var (
    25  	// dbMetadata is the header that gets applied to the database to identify a
    26  	// version and indicate what type of data is being stored in the database.
    27  	dbMetadata = persist.Metadata{
    28  		Header:  "Sia Storage Manager DB",
    29  		Version: "0.6.0",
    30  	}
    31  
    32  	// persistMetadata is the header that gets added to the persist file to
    33  	// identify the type of file and the version of the file.
    34  	persistMetadata = persist.Metadata{
    35  		Header:  "Sia Storage Manager",
    36  		Version: "0.6.0",
    37  	}
    38  
    39  	errStorageManagerClosed = errors.New("call is disabled because storage manager is closed")
    40  )
    41  
    42  // StorageManager tracks multiple storage folders, and is responsible for
    43  // adding sectors, removing sectors, and overall managing the way that data is
    44  // stored.
    45  type StorageManager struct {
    46  	// Dependencies.
    47  	dependencies
    48  
    49  	// Storage management information.
    50  	sectorSalt     crypto.Hash
    51  	storageFolders []*storageFolder
    52  
    53  	// Utilities.
    54  	db         *persist.BoltDatabase
    55  	log        *persist.Logger
    56  	mu         sync.RWMutex
    57  	persistDir string
    58  
    59  	// The resource lock is held by threaded functions for the duration of
    60  	// their operation. Functions should grab the resource lock as a read lock
    61  	// unless they are planning on manipulating the 'closed' variable.
    62  	// Readlocks are used so that multiple functions can use resources
    63  	// simultaneously, but the resources are not closed until all functions
    64  	// accessing them have returned.
    65  	closed       bool
    66  	resourceLock sync.RWMutex
    67  }
    68  
    69  // Close will shut down the storage manager.
    70  func (sm *StorageManager) Close() (composedError error) {
    71  	// Grab the resource lock and indicate that the host is closing. Concurrent
    72  	// functions hold the resource lock until they terminate, meaning that no
    73  	// threaded function will be running by the time the resource lock is
    74  	// acquired.
    75  	sm.resourceLock.Lock()
    76  	closed := sm.closed
    77  	sm.closed = true
    78  	sm.resourceLock.Unlock()
    79  	if closed {
    80  		return nil
    81  	}
    82  
    83  	// Close the bolt database.
    84  	err := sm.db.Close()
    85  	if err != nil {
    86  		composedError = composeErrors(composedError, err)
    87  	}
    88  
    89  	// Save the latest host state.
    90  	sm.mu.Lock()
    91  	err = sm.saveSync()
    92  	sm.mu.Unlock()
    93  	if err != nil {
    94  		composedError = composeErrors(composedError, err)
    95  	}
    96  
    97  	// Close the logger. The logger should be the last thing to shut down so
    98  	// that all other objects have access to logging while closing.
    99  	err = sm.log.Close()
   100  	if err != nil {
   101  		composedError = composeErrors(composedError, err)
   102  	}
   103  	return composedError
   104  }
   105  
   106  // newStorageManager creates a new storage manager.
   107  func newStorageManager(dependencies dependencies, persistDir string) (*StorageManager, error) {
   108  	sm := &StorageManager{
   109  		dependencies: dependencies,
   110  
   111  		persistDir: persistDir,
   112  	}
   113  
   114  	// Create the perist directory if it does not yet exist.
   115  	err := dependencies.mkdirAll(sm.persistDir, 0700)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	// Initialize the logger. Logging should be initialized ASAP, because the
   121  	// rest of the initialization makes use of the logger.
   122  	sm.log, err = dependencies.newLogger(filepath.Join(sm.persistDir, logFile))
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  
   127  	// Open the database containing the host's storage obligation metadata.
   128  	sm.db, err = dependencies.openDatabase(dbMetadata, filepath.Join(sm.persistDir, dbFilename))
   129  	if err != nil {
   130  		// An error will be returned if the database has the wrong version, but
   131  		// as of writing there was only one version of the database and all
   132  		// other databases would be incompatible.
   133  		_ = sm.log.Close()
   134  		return nil, err
   135  	}
   136  	// After opening the database, it must be initialized. Most commonly,
   137  	// nothing happens. But for new databases, a set of buckets must be
   138  	// created. Initialization is also a good time to run sanity checks.
   139  	err = sm.initDB()
   140  	if err != nil {
   141  		_ = sm.log.Close()
   142  		_ = sm.db.Close()
   143  		return nil, err
   144  	}
   145  
   146  	// Load the prior persistence structures.
   147  	err = sm.load()
   148  	if err != nil {
   149  		_ = sm.log.Close()
   150  		_ = sm.db.Close()
   151  		return nil, err
   152  	}
   153  	return sm, nil
   154  }
   155  
   156  // New returns an initialized StorageManager.
   157  func New(persistDir string) (*StorageManager, error) {
   158  	return newStorageManager(productionDependencies{}, persistDir)
   159  }