github.com/dashpay/godash@v0.0.0-20160726055534-e038a21e0e3d/btcd.go (about)

     1  // Copyright (c) 2013-2016 The btcsuite developers
     2  // Copyright (c) 2016 The Dash developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package main
     7  
     8  import (
     9  	"fmt"
    10  	"net"
    11  	"net/http"
    12  	_ "net/http/pprof"
    13  	"os"
    14  	"runtime"
    15  	"runtime/debug"
    16  	"runtime/pprof"
    17  
    18  	"github.com/dashpay/godash/blockchain/indexers"
    19  	"github.com/dashpay/godash/limits"
    20  )
    21  
    22  var (
    23  	cfg             *config
    24  	shutdownChannel = make(chan struct{})
    25  )
    26  
    27  // winServiceMain is only invoked on Windows.  It detects when btcd is running
    28  // as a service and reacts accordingly.
    29  var winServiceMain func() (bool, error)
    30  
    31  // btcdMain is the real main function for btcd.  It is necessary to work around
    32  // the fact that deferred functions do not run when os.Exit() is called.  The
    33  // optional serverChan parameter is mainly used by the service code to be
    34  // notified with the server once it is setup so it can gracefully stop it when
    35  // requested from the service control manager.
    36  func btcdMain(serverChan chan<- *server) error {
    37  	// Load configuration and parse command line.  This function also
    38  	// initializes logging and configures it accordingly.
    39  	tcfg, _, err := loadConfig()
    40  	if err != nil {
    41  		return err
    42  	}
    43  	cfg = tcfg
    44  	defer backendLog.Flush()
    45  
    46  	// Show version at startup.
    47  	btcdLog.Infof("Version %s", version())
    48  
    49  	// Enable http profiling server if requested.
    50  	if cfg.Profile != "" {
    51  		go func() {
    52  			listenAddr := net.JoinHostPort("", cfg.Profile)
    53  			btcdLog.Infof("Profile server listening on %s", listenAddr)
    54  			profileRedirect := http.RedirectHandler("/debug/pprof",
    55  				http.StatusSeeOther)
    56  			http.Handle("/", profileRedirect)
    57  			btcdLog.Errorf("%v", http.ListenAndServe(listenAddr, nil))
    58  		}()
    59  	}
    60  
    61  	// Write cpu profile if requested.
    62  	if cfg.CPUProfile != "" {
    63  		f, err := os.Create(cfg.CPUProfile)
    64  		if err != nil {
    65  			btcdLog.Errorf("Unable to create cpu profile: %v", err)
    66  			return err
    67  		}
    68  		pprof.StartCPUProfile(f)
    69  		defer f.Close()
    70  		defer pprof.StopCPUProfile()
    71  	}
    72  
    73  	// Perform upgrades to btcd as new versions require it.
    74  	if err := doUpgrades(); err != nil {
    75  		btcdLog.Errorf("%v", err)
    76  		return err
    77  	}
    78  
    79  	// Load the block database.
    80  	db, err := loadBlockDB()
    81  	if err != nil {
    82  		btcdLog.Errorf("%v", err)
    83  		return err
    84  	}
    85  	defer db.Close()
    86  
    87  	// Ensure the database is sync'd and closed on Ctrl+C.
    88  	addInterruptHandler(func() {
    89  		btcdLog.Infof("Gracefully shutting down the database...")
    90  		db.Close()
    91  	})
    92  
    93  	// Drop indexes and exit if requested.
    94  	//
    95  	// NOTE: The order is important here because dropping the tx index also
    96  	// drops the address index since it relies on it.
    97  	if cfg.DropAddrIndex {
    98  		if err := indexers.DropAddrIndex(db); err != nil {
    99  			btcdLog.Errorf("%v", err)
   100  			return err
   101  		}
   102  
   103  		return nil
   104  	}
   105  	if cfg.DropTxIndex {
   106  		if err := indexers.DropTxIndex(db); err != nil {
   107  			btcdLog.Errorf("%v", err)
   108  			return err
   109  		}
   110  
   111  		return nil
   112  	}
   113  
   114  	// Create server and start it.
   115  	server, err := newServer(cfg.Listeners, db, activeNetParams.Params)
   116  	if err != nil {
   117  		// TODO(oga) this logging could do with some beautifying.
   118  		btcdLog.Errorf("Unable to start server on %v: %v",
   119  			cfg.Listeners, err)
   120  		return err
   121  	}
   122  	addInterruptHandler(func() {
   123  		btcdLog.Infof("Gracefully shutting down the server...")
   124  		server.Stop()
   125  		server.WaitForShutdown()
   126  	})
   127  	server.Start()
   128  	if serverChan != nil {
   129  		serverChan <- server
   130  	}
   131  
   132  	// Monitor for graceful server shutdown and signal the main goroutine
   133  	// when done.  This is done in a separate goroutine rather than waiting
   134  	// directly so the main goroutine can be signaled for shutdown by either
   135  	// a graceful shutdown or from the main interrupt handler.  This is
   136  	// necessary since the main goroutine must be kept running long enough
   137  	// for the interrupt handler goroutine to finish.
   138  	go func() {
   139  		server.WaitForShutdown()
   140  		srvrLog.Infof("Server shutdown complete")
   141  		shutdownChannel <- struct{}{}
   142  	}()
   143  
   144  	// Wait for shutdown signal from either a graceful server stop or from
   145  	// the interrupt handler.
   146  	<-shutdownChannel
   147  	btcdLog.Info("Shutdown complete")
   148  	return nil
   149  }
   150  
   151  func main() {
   152  	// Use all processor cores.
   153  	runtime.GOMAXPROCS(runtime.NumCPU())
   154  
   155  	// Block and transaction processing can cause bursty allocations.  This
   156  	// limits the garbage collector from excessively overallocating during
   157  	// bursts.  This value was arrived at with the help of profiling live
   158  	// usage.
   159  	debug.SetGCPercent(10)
   160  
   161  	// Up some limits.
   162  	if err := limits.SetLimits(); err != nil {
   163  		fmt.Fprintf(os.Stderr, "failed to set limits: %v\n", err)
   164  		os.Exit(1)
   165  	}
   166  
   167  	// Call serviceMain on Windows to handle running as a service.  When
   168  	// the return isService flag is true, exit now since we ran as a
   169  	// service.  Otherwise, just fall through to normal operation.
   170  	if runtime.GOOS == "windows" {
   171  		isService, err := winServiceMain()
   172  		if err != nil {
   173  			fmt.Println(err)
   174  			os.Exit(1)
   175  		}
   176  		if isService {
   177  			os.Exit(0)
   178  		}
   179  	}
   180  
   181  	// Work around defer not working after os.Exit()
   182  	if err := btcdMain(nil); err != nil {
   183  		os.Exit(1)
   184  	}
   185  }