// logSnapshot logs about the snapshot that was taken. func (s *Server) logSnapshot(err error, currentIndex, count uint64) { info := fmt.Sprintf("%s: snapshot of %d events at index %d", s.connectionString(), count, currentIndex) if err != nil { log.Infof("%s attempted and failed: %v", info, err) } else { log.Infof("%s completed", info) } }
// Join joins to the leader of an existing cluster. func (s *Server) Join(leader string) error { command := &raft.DefaultJoinCommand{ Name: s.raftServer.Name(), ConnectionString: s.connectionString(), } var b bytes.Buffer if err := json.NewEncoder(&b).Encode(command); err != nil { return nil } resp, err := http.Post(fmt.Sprintf("http://%s/join", leader), "application/json", &b) if err != nil { return err } defer func() { _ = resp.Body.Close() }() // Look for redirect. if resp.StatusCode == http.StatusTemporaryRedirect { leader := resp.Header.Get("Location") if leader == "" { return errors.New("Redirect requested, but no location header supplied") } u, err := url.Parse(leader) if err != nil { return errors.New("Failed to parse redirect location") } log.Infof("Redirecting to leader at %s", u.Host) return s.Join(u.Host) } return nil }
func main() { flag.Parse() // Set up profiling, if requested. if cpuprofile != "" { log.Info("Profiling enabled") f, err := os.Create(cpuprofile) if err != nil { log.Errorf("Unable to create path: %s", err.Error()) } defer closeFile(f) err = pprof.StartCPUProfile(f) if err != nil { log.Errorf("Unable to start CPU Profile: %s", err.Error()) } defer pprof.StopCPUProfile() } // Set logging log.SetLevel(logLevel) if logFile != "stdout" { f := createFile(logFile) defer closeFile(f) log.Infof("Redirecting logging to %s", logFile) log.SetOutput(f) } // Set the data directory. if flag.NArg() == 0 { flag.Usage() println("Data path argument required") log.Error("No data path supplied -- aborting") os.Exit(1) } dataPath := flag.Arg(0) createDir(dataPath) s := server.NewServer(dataPath, dbfile, snapAfter, host, port) go func() { log.Error(s.ListenAndServe(join).Error()) }() if !disableReporting { reportLaunch() } terminate := make(chan os.Signal, 1) signal.Notify(terminate, os.Interrupt) <-terminate log.Info("rqlite server stopped") }
// ListenAndServe starts the server. func (s *Server) ListenAndServe(leader string) error { var err error log.Infof("Initializing Raft Server: %s", s.path) // Initialize and start Raft server. transporter := raft.NewHTTPTransporter("/raft", 200*time.Millisecond) stateMachine := NewDbStateMachine(s.dbPath) s.raftServer, err = raft.NewServer(s.name, s.path, transporter, stateMachine, s.db, "") if err != nil { log.Errorf("Failed to create new Raft server: %s", err.Error()) return err } log.Info("Loading latest snapshot, if any, from disk") if err := s.raftServer.LoadSnapshot(); err != nil && os.IsNotExist(err) { log.Info("no snapshot found") } else if err != nil { log.Errorf("Error loading snapshot: %s", err.Error()) } transporter.Install(s.raftServer, s) if err := s.raftServer.Start(); err != nil { log.Errorf("Error starting raft server: %s", err.Error()) } if leader != "" { // Join to leader if specified. log.Infof("Attempting to join leader at %s", leader) if !s.raftServer.IsLogEmpty() { log.Error("Cannot join with an existing log") return errors.New("Cannot join with an existing log") } if err := s.Join(leader); err != nil { log.Errorf("Failed to join leader: %s", err.Error()) return err } } else if s.raftServer.IsLogEmpty() { // Initialize the server by joining itself. log.Info("Initializing new cluster") _, err := s.raftServer.Do(&raft.DefaultJoinCommand{ Name: s.raftServer.Name(), ConnectionString: s.connectionString(), }) if err != nil { log.Errorf("Failed to join to self: %s", err.Error()) } } else { log.Info("Recovered from log") } log.Info("Initializing HTTP server") // Initialize and start HTTP server. s.httpServer = &http.Server{ Addr: fmt.Sprintf(":%d", s.port), Handler: s.router, } s.router.HandleFunc("/statistics", s.serveStatistics).Methods("GET") s.router.HandleFunc("/diagnostics", s.serveDiagnostics).Methods("GET") s.router.HandleFunc("/raft", s.serveRaftInfo).Methods("GET") s.router.HandleFunc("/db", s.readHandler).Methods("GET") s.router.HandleFunc("/db", s.writeHandler).Methods("POST") s.router.HandleFunc("/join", s.joinHandler).Methods("POST") log.Infof("Listening at %s", s.connectionString()) return s.httpServer.ListenAndServe() }