func NewPostgresKeeper(id string, cfg config, stop chan bool, end chan error) (*PostgresKeeper, error) { etcdPath := filepath.Join(common.EtcdBasePath, cfg.clusterName) e, err := etcdm.NewEtcdManager(cfg.etcdEndpoints, etcdPath, common.DefaultEtcdRequestTimeout) if err != nil { return nil, fmt.Errorf("cannot create etcd manager: %v", err) } clusterConfig, _, err := e.GetClusterConfig() if err != nil { return nil, fmt.Errorf("cannot get cluster config: %v", err) } log.Debugf(spew.Sprintf("clusterConfig: %#v", clusterConfig)) p := &PostgresKeeper{id: id, dataDir: cfg.dataDir, e: e, listenAddress: cfg.listenAddress, port: cfg.port, pgListenAddress: cfg.pgListenAddress, pgPort: cfg.pgPort, clusterConfig: clusterConfig, stop: stop, end: end, } serverParameters := p.createServerParameters() pgm, err := postgresql.NewManager(id, cfg.pgBinPath, cfg.dataDir, serverParameters, p.getOurConnString(), p.getOurReplConnString(), clusterConfig.PGReplUser, clusterConfig.PGReplPassword, clusterConfig.RequestTimeout) if err != nil { return nil, fmt.Errorf("cannot create postgres manager: %v", err) } p.pgm = pgm return p, nil }
func NewPostgresKeeper(id string, cfg config, stop chan bool, end chan error) (*PostgresKeeper, error) { etcdPath := filepath.Join(common.EtcdBasePath, cfg.clusterName) e, err := etcdm.NewEtcdManager(cfg.etcdEndpoints, etcdPath, common.DefaultEtcdRequestTimeout) if err != nil { return nil, fmt.Errorf("cannot create etcd manager: %v", err) } cd, _, err := e.GetClusterData() if err != nil { return nil, fmt.Errorf("error retrieving cluster data: %v", err) } var cv *cluster.ClusterView if cd == nil { cv = cluster.NewClusterView() } else { cv = cd.ClusterView } log.Debugf(spew.Sprintf("clusterView: %#v", cv)) clusterConfig := cv.Config.ToConfig() log.Debugf(spew.Sprintf("clusterConfig: %#v", clusterConfig)) p := &PostgresKeeper{id: id, dataDir: cfg.dataDir, e: e, listenAddress: cfg.listenAddress, port: cfg.port, pgListenAddress: cfg.pgListenAddress, pgPort: cfg.pgPort, clusterConfig: clusterConfig, stop: stop, end: end, } followersIDs := cv.GetFollowersIDs(p.id) pgParameters := p.createPGParameters(followersIDs) pgm, err := postgresql.NewManager(id, cfg.pgBinPath, cfg.dataDir, cfg.pgConfDir, pgParameters, p.getOurConnString(), p.getOurReplConnString(), clusterConfig.PGReplUser, clusterConfig.PGReplPassword, clusterConfig.RequestTimeout) if err != nil { return nil, fmt.Errorf("cannot create postgres manager: %v", err) } p.pgm = pgm return p, nil }
func (p *PostgresKeeper) Start() { endSMCh := make(chan struct{}) endPgStatecheckerCh := make(chan struct{}) endApiCh := make(chan error) var err error var cd *cluster.ClusterData // TODO(sgotti) make the postgres manager stateless and instantiate a // new one at every check loop, this will avoid the need to loop here // to get the clusterconfig for { cd, _, err = p.e.GetClusterData() if err == nil { break } log.Errorf("error retrieving cluster data: %v", err) time.Sleep(cluster.DefaultSleepInterval) } var cv *cluster.ClusterView if cd == nil { cv = cluster.NewClusterView() } else { cv = cd.ClusterView } log.Debugf(spew.Sprintf("clusterView: %#v", cv)) p.clusterConfig = cv.Config.ToConfig() log.Debugf(spew.Sprintf("clusterConfig: %#v", p.clusterConfig)) if err := p.loadCVVersion(); err != nil { p.end <- fmt.Errorf("failed to load cluster version file: %v", err) return } // TODO(sgotti) reconfigure the various configurations options (PGRepl* // and RequestTimeout) after a changed cluster config followersIDs := cv.GetFollowersIDs(p.id) pgParameters := p.createPGParameters(followersIDs) pgm := postgresql.NewManager(p.id, cfg.pgBinPath, cfg.dataDir, cfg.pgConfDir, pgParameters, p.getOurConnString(), p.getOurReplConnString(), p.clusterConfig.PGReplUser, p.clusterConfig.PGReplPassword, p.clusterConfig.RequestTimeout) p.pgm = pgm p.pgm.Stop(true) http.HandleFunc("/info", p.infoHandler) http.HandleFunc("/pgstate", p.pgStateHandler) go func() { endApiCh <- http.ListenAndServe(fmt.Sprintf("%s:%s", p.listenAddress, p.port), nil) }() ctx, cancel := context.WithCancel(context.Background()) smTimerCh := time.NewTimer(0).C updatePGStateTimerCh := time.NewTimer(0).C for true { select { case <-p.stop: log.Debugf("stopping stolon keeper") cancel() p.pgm.Stop(true) p.end <- nil return case <-smTimerCh: go func() { p.postgresKeeperSM(ctx) endSMCh <- struct{}{} }() case <-endSMCh: smTimerCh = time.NewTimer(p.clusterConfig.SleepInterval).C case <-updatePGStateTimerCh: go func() { p.updatePGState(ctx) endPgStatecheckerCh <- struct{}{} }() case <-endPgStatecheckerCh: updatePGStateTimerCh = time.NewTimer(p.clusterConfig.SleepInterval).C case err := <-endApiCh: if err != nil { log.Fatal("ListenAndServe: ", err) } close(p.stop) } } }
func (p *PostgresKeeper) Start() { endSMCh := make(chan struct{}) endPgStatecheckerCh := make(chan struct{}) endUpdateKeeperInfo := make(chan struct{}) var err error var cd *cluster.ClusterData cd, _, err = p.e.GetClusterData() if err != nil { log.Error("error retrieving cluster data", zap.Error(err)) } else if cd != nil { if cd.FormatVersion != cluster.CurrentCDFormatVersion { log.Error("unsupported clusterdata format version", zap.Uint64("version", cd.FormatVersion)) } else if cd.Cluster != nil { p.sleepInterval = cd.Cluster.Spec.SleepInterval.Duration p.requestTimeout = cd.Cluster.Spec.RequestTimeout.Duration } } log.Debug("cd dump", zap.String("cd", spew.Sdump(cd))) // TODO(sgotti) reconfigure the various configurations options // (RequestTimeout) after a changed cluster config pgParameters := make(common.Parameters) pgm := postgresql.NewManager(p.pgBinPath, p.dataDir, pgParameters, p.getLocalConnParams(), p.getOurReplConnParams(), p.pgSUUsername, p.pgSUPassword, p.pgReplUsername, p.pgReplPassword, p.requestTimeout) p.pgm = pgm p.pgm.Stop(true) ctx, cancel := context.WithCancel(context.Background()) smTimerCh := time.NewTimer(0).C updatePGStateTimerCh := time.NewTimer(0).C updateKeeperInfoTimerCh := time.NewTimer(0).C for true { select { case <-p.stop: log.Debug("stopping stolon keeper") cancel() p.pgm.Stop(true) p.end <- nil return case <-smTimerCh: go func() { p.postgresKeeperSM(ctx) endSMCh <- struct{}{} }() case <-endSMCh: smTimerCh = time.NewTimer(p.sleepInterval).C case <-updatePGStateTimerCh: // updateKeeperInfo two times faster than the sleep interval go func() { p.updatePGState(ctx) endPgStatecheckerCh <- struct{}{} }() case <-endPgStatecheckerCh: // updateKeeperInfo two times faster than the sleep interval updatePGStateTimerCh = time.NewTimer(p.sleepInterval / 2).C case <-updateKeeperInfoTimerCh: go func() { if err := p.updateKeeperInfo(); err != nil { log.Error("failed to update keeper info", zap.Error(err)) } endUpdateKeeperInfo <- struct{}{} }() case <-endUpdateKeeperInfo: updateKeeperInfoTimerCh = time.NewTimer(p.sleepInterval).C } } }