// NewServer returns a new instance of Server built from a config. func NewServer(c *Config, buildInfo *BuildInfo) (*Server, error) { // We need to ensure that a meta directory always exists even if // we don't start the meta store. node.json is always stored under // the meta directory. if err := os.MkdirAll(c.Meta.Dir, 0777); err != nil { return nil, fmt.Errorf("mkdir all: %s", err) } // 0.10-rc1 and prior would sometimes put the node.json at the root // dir which breaks backup/restore and restarting nodes. This moves // the file from the root so it's always under the meta dir. oldPath := filepath.Join(filepath.Dir(c.Meta.Dir), "node.json") newPath := filepath.Join(c.Meta.Dir, "node.json") if _, err := os.Stat(oldPath); err == nil { if err := os.Rename(oldPath, newPath); err != nil { return nil, err } } _, err := influxdb.LoadNode(c.Meta.Dir) if err != nil { if !os.IsNotExist(err) { return nil, err } } // Check to see if there is a raft db, if so, error out with a message // to downgrade, export, and then import the meta data raftFile := filepath.Join(c.Meta.Dir, "raft.db") if _, err := os.Stat(raftFile); err == nil { return nil, fmt.Errorf("detected %s. To proceed, you'll need to either 1) downgrade to v0.11.x, export your metadata, upgrade to the current version again, and then import the metadata or 2) delete the file, which will effectively reset your database. For more assistance with the upgrade, see: https://docs.influxdata.com/influxdb/v0.12/administration/upgrading/", raftFile) } // In 0.10.0 bind-address got moved to the top level. Check // The old location to keep things backwards compatible bind := c.BindAddress s := &Server{ buildInfo: *buildInfo, err: make(chan error), closing: make(chan struct{}), BindAddress: bind, MetaClient: meta.NewClient(c.Meta), Monitor: monitor.New(c.Monitor), reportingDisabled: c.ReportingDisabled, httpAPIAddr: c.HTTPD.BindAddress, httpUseTLS: c.HTTPD.HTTPSEnabled, tcpAddr: bind, config: c, } if err := s.MetaClient.Open(); err != nil { return nil, err } s.TSDBStore = tsdb.NewStore(c.Data.Dir) s.TSDBStore.EngineOptions.Config = c.Data // Copy TSDB configuration. s.TSDBStore.EngineOptions.EngineVersion = c.Data.Engine // Create the Subscriber service s.Subscriber = subscriber.NewService(c.Subscriber) // Initialize points writer. s.PointsWriter = cluster.NewPointsWriter() s.PointsWriter.WriteTimeout = time.Duration(c.Cluster.WriteTimeout) s.PointsWriter.TSDBStore = s.TSDBStore s.PointsWriter.Subscriber = s.Subscriber // Initialize query executor. s.QueryExecutor = cluster.NewQueryExecutor() s.QueryExecutor.MetaClient = s.MetaClient s.QueryExecutor.TSDBStore = s.TSDBStore s.QueryExecutor.Monitor = s.Monitor s.QueryExecutor.PointsWriter = s.PointsWriter s.QueryExecutor.QueryTimeout = time.Duration(c.Cluster.QueryTimeout) s.QueryExecutor.QueryManager = influxql.DefaultQueryManager(c.Cluster.MaxConcurrentQueries) s.QueryExecutor.MaxSelectPointN = c.Cluster.MaxSelectPointN s.QueryExecutor.MaxSelectSeriesN = c.Cluster.MaxSelectSeriesN s.QueryExecutor.MaxSelectBucketsN = c.Cluster.MaxSelectBucketsN if c.Data.QueryLogEnabled { s.QueryExecutor.LogOutput = os.Stderr } // Initialize the monitor s.Monitor.Version = s.buildInfo.Version s.Monitor.Commit = s.buildInfo.Commit s.Monitor.Branch = s.buildInfo.Branch s.Monitor.BuildTime = s.buildInfo.Time s.Monitor.PointsWriter = (*monitorPointsWriter)(s.PointsWriter) return s, nil }
func TestPointsWriter_WritePoints(t *testing.T) { tests := []struct { name string database string retentionPolicy string // the responses returned by each shard write call. node ID 1 = pos 0 err []error expErr error }{ { name: "write one success", database: "mydb", retentionPolicy: "myrp", err: []error{nil, nil, nil}, expErr: nil, }, // Write to non-existent database { name: "write to non-existent database", database: "doesnt_exist", retentionPolicy: "", err: []error{nil, nil, nil}, expErr: fmt.Errorf("database not found: doesnt_exist"), }, } for _, test := range tests { pr := &cluster.WritePointsRequest{ Database: test.database, RetentionPolicy: test.retentionPolicy, } // Three points that range over the shardGroup duration (1h) and should map to two // distinct shards pr.AddPoint("cpu", 1.0, time.Unix(0, 0), nil) pr.AddPoint("cpu", 2.0, time.Unix(0, 0).Add(time.Hour), nil) pr.AddPoint("cpu", 3.0, time.Unix(0, 0).Add(time.Hour+time.Second), nil) // copy to prevent data race theTest := test sm := cluster.NewShardMapping() sm.MapPoint( &meta.ShardInfo{ID: uint64(1), Owners: []meta.ShardOwner{ {NodeID: 1}, {NodeID: 2}, {NodeID: 3}, }}, pr.Points[0]) sm.MapPoint( &meta.ShardInfo{ID: uint64(2), Owners: []meta.ShardOwner{ {NodeID: 1}, {NodeID: 2}, {NodeID: 3}, }}, pr.Points[1]) sm.MapPoint( &meta.ShardInfo{ID: uint64(2), Owners: []meta.ShardOwner{ {NodeID: 1}, {NodeID: 2}, {NodeID: 3}, }}, pr.Points[2]) // Local cluster.Node ShardWriter // lock on the write increment since these functions get called in parallel var mu sync.Mutex sw := &fakeShardWriter{ ShardWriteFn: func(shardID, nodeID uint64, points []models.Point) error { mu.Lock() defer mu.Unlock() return theTest.err[int(nodeID)-1] }, } store := &fakeStore{ WriteFn: func(shardID uint64, points []models.Point) error { mu.Lock() defer mu.Unlock() return theTest.err[0] }, } hh := &fakeShardWriter{ ShardWriteFn: func(shardID, nodeID uint64, points []models.Point) error { return nil }, } ms := NewPointsWriterMetaClient() ms.DatabaseFn = func(database string) (*meta.DatabaseInfo, error) { return nil, nil } ms.NodeIDFn = func() uint64 { return 1 } subPoints := make(chan *cluster.WritePointsRequest, 1) sub := Subscriber{} sub.PointsFn = func() chan<- *cluster.WritePointsRequest { return subPoints } c := cluster.NewPointsWriter() c.MetaClient = ms c.ShardWriter = sw c.TSDBStore = store c.HintedHandoff = hh c.Subscriber = sub c.Node = &influxdb.Node{ID: 1} c.Open() defer c.Close() err := c.WritePoints(pr.Database, pr.RetentionPolicy, models.ConsistencyLevelOne, pr.Points) if err == nil && test.expErr != nil { t.Errorf("PointsWriter.WritePoints(): '%s' error: got %v, exp %v", test.name, err, test.expErr) } if err != nil && test.expErr == nil { t.Errorf("PointsWriter.WritePoints(): '%s' error: got %v, exp %v", test.name, err, test.expErr) } if err != nil && test.expErr != nil && err.Error() != test.expErr.Error() { t.Errorf("PointsWriter.WritePoints(): '%s' error: got %v, exp %v", test.name, err, test.expErr) } if test.expErr == nil { select { case p := <-subPoints: if !reflect.DeepEqual(p, pr) { t.Errorf("PointsWriter.WritePoints(): '%s' error: unexpected WritePointsRequest got %v, exp %v", test.name, p, pr) } default: t.Errorf("PointsWriter.WritePoints(): '%s' error: Subscriber.Points not called", test.name) } } } }