2013-08-06 23:55:22 +02:00
|
|
|
// Copyright (c) 2013 Conformal Systems LLC.
|
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net"
|
2013-09-17 23:40:27 +02:00
|
|
|
"net/http"
|
|
|
|
_ "net/http/pprof"
|
2013-08-06 23:55:22 +02:00
|
|
|
"os"
|
|
|
|
"runtime"
|
2013-10-26 23:12:54 +02:00
|
|
|
"runtime/pprof"
|
2013-08-06 23:55:22 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2013-10-26 23:02:23 +02:00
|
|
|
cfg *config
|
|
|
|
shutdownChannel = make(chan bool)
|
2013-08-06 23:55:22 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// btcdMain is the real main function for btcd. It is necessary to work around
|
|
|
|
// the fact that deferred functions do not run when os.Exit() is called.
|
|
|
|
func btcdMain() error {
|
|
|
|
// Initialize logging and setup deferred flushing to ensure all
|
|
|
|
// outstanding messages are written on shutdown.
|
|
|
|
loggers := setLogLevel(defaultLogLevel)
|
|
|
|
defer func() {
|
|
|
|
for _, logger := range loggers {
|
|
|
|
logger.Flush()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Load configuration and parse command line.
|
|
|
|
tcfg, _, err := loadConfig()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cfg = tcfg
|
|
|
|
|
|
|
|
// Change the logging level if needed.
|
|
|
|
if cfg.DebugLevel != defaultLogLevel {
|
|
|
|
loggers = setLogLevel(cfg.DebugLevel)
|
|
|
|
}
|
|
|
|
|
2013-10-15 22:54:00 +02:00
|
|
|
// Show version at startup.
|
|
|
|
log.Infof("Version %s", version())
|
|
|
|
|
2013-10-26 23:12:54 +02:00
|
|
|
// Enable http profiling server if requested.
|
2013-09-17 23:40:27 +02:00
|
|
|
if cfg.Profile != "" {
|
|
|
|
go func() {
|
2013-09-18 00:15:49 +02:00
|
|
|
listenAddr := net.JoinHostPort("", cfg.Profile)
|
2013-10-11 03:28:41 +02:00
|
|
|
log.Infof("Profile server listening on %s", listenAddr)
|
2013-10-23 17:48:17 +02:00
|
|
|
profileRedirect := http.RedirectHandler("/debug/pprof",
|
|
|
|
http.StatusSeeOther)
|
|
|
|
http.Handle("/", profileRedirect)
|
2013-09-18 00:15:49 +02:00
|
|
|
log.Errorf("%v", http.ListenAndServe(listenAddr, nil))
|
2013-09-17 23:40:27 +02:00
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2013-10-26 23:12:54 +02:00
|
|
|
// Write cpu profile if requested.
|
|
|
|
if cfg.CpuProfile != "" {
|
|
|
|
f, err := os.Create(cfg.CpuProfile)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Unable to create cpu profile: %v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
pprof.StartCPUProfile(f)
|
|
|
|
defer pprof.StopCPUProfile()
|
|
|
|
}
|
|
|
|
|
2013-09-15 20:39:28 +02:00
|
|
|
// Perform upgrades to btcd as new versions require it.
|
2013-10-08 02:24:44 +02:00
|
|
|
if err := doUpgrades(); err != nil {
|
2013-09-15 20:39:28 +02:00
|
|
|
log.Errorf("%v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2013-08-06 23:55:22 +02:00
|
|
|
// Load the block database.
|
|
|
|
db, err := loadBlockDB()
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("%v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer db.Close()
|
|
|
|
|
|
|
|
// Ensure the database is sync'd and closed on Ctrl+C.
|
|
|
|
addInterruptHandler(func() {
|
2013-10-26 23:02:23 +02:00
|
|
|
log.Infof("Gracefully shutting down the database...")
|
2013-08-06 23:55:22 +02:00
|
|
|
db.RollbackClose()
|
|
|
|
})
|
|
|
|
|
|
|
|
// Create server and start it.
|
|
|
|
listenAddr := net.JoinHostPort("", cfg.Port)
|
|
|
|
server, err := newServer(listenAddr, db, activeNetParams.btcnet)
|
|
|
|
if err != nil {
|
2013-10-15 18:17:23 +02:00
|
|
|
log.Errorf("Unable to start server on %v: %v", listenAddr, err)
|
2013-08-06 23:55:22 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
server.Start()
|
|
|
|
|
2013-10-26 23:02:23 +02:00
|
|
|
// Monitor for graceful server shutdown and signal the main goroutine
|
|
|
|
// when done. This is done in a separate goroutine rather than waiting
|
|
|
|
// directly so the main goroutine can be signaled for shutdown by either
|
|
|
|
// a graceful shutdown or from the main interrupt handler. This is
|
|
|
|
// necessary since the main goroutine must be kept running long enough
|
|
|
|
// for the interrupt handler goroutine to finish.
|
|
|
|
go func() {
|
|
|
|
server.WaitForShutdown()
|
|
|
|
shutdownChannel <- true
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Wait for shutdown signal from either a graceful server stop or from
|
|
|
|
// the interrupt handler.
|
|
|
|
<-shutdownChannel
|
|
|
|
log.Info("Shutdown complete")
|
2013-08-06 23:55:22 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
// Use all processor cores.
|
|
|
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
|
|
|
|
2013-10-07 23:24:19 +02:00
|
|
|
// Up some limits.
|
2013-10-08 02:24:44 +02:00
|
|
|
if err := setLimits(); err != nil {
|
2013-10-07 23:24:19 +02:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2013-08-06 23:55:22 +02:00
|
|
|
// Work around defer not working after os.Exit()
|
2013-10-08 02:24:44 +02:00
|
|
|
if err := btcdMain(); err != nil {
|
2013-08-06 23:55:22 +02:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|