// writeDatabaseInfo will write the relative paths of all shards in the database on // this server into the connection func (s *Service) writeDatabaseInfo(conn net.Conn, database string) error { res := Response{} db, err := s.MetaClient.Database(database) if err != nil { return err } if db == nil { return influxdb.ErrDatabaseNotFound(database) } for _, rp := range db.RetentionPolicies { for _, sg := range rp.ShardGroups { for _, sh := range sg.Shards { // ignore if the shard isn't on the server if s.TSDBStore.Shard(sh.ID) == nil { continue } path, err := s.TSDBStore.ShardRelativePath(sh.ID) if err != nil { return err } res.Paths = append(res.Paths, path) } } } if err := json.NewEncoder(conn).Encode(res); err != nil { return fmt.Errorf("encode resonse: %s", err.Error()) } return nil }
func (e *QueryExecutor) normalizeMeasurement(m *influxql.Measurement, defaultDatabase string) error { // Targets (measurements in an INTO clause) can have blank names, which means it will be // the same as the measurement name it came from in the FROM clause. if !m.IsTarget && m.Name == "" && m.Regex == nil { return errors.New("invalid measurement") } // Measurement does not have an explicit database? Insert default. if m.Database == "" { m.Database = defaultDatabase } // The database must now be specified by this point. if m.Database == "" { return errors.New("database name required") } // Find database. di, err := e.MetaClient.Database(m.Database) if err != nil { return err } else if di == nil { return influxdb.ErrDatabaseNotFound(m.Database) } // If no retention policy was specified, use the default. if m.RetentionPolicy == "" { if di.DefaultRetentionPolicy == "" { return fmt.Errorf("default retention policy not set for: %s", di.Name) } m.RetentionPolicy = di.DefaultRetentionPolicy } return nil }
// CreateContinuousQuery adds a named continuous query to a database. func (data *Data) CreateContinuousQuery(database, name, query string) error { di := data.Database(database) if di == nil { return influxdb.ErrDatabaseNotFound(database) } // Ensure the name doesn't already exist. for _, cq := range di.ContinuousQueries { if cq.Name == name { // If the query string is the same, we'll silently return, // otherwise we'll assume the user might be trying to // overwrite an existing CQ with a different query. if strings.ToLower(cq.Query) == strings.ToLower(query) { return nil } return ErrContinuousQueryExists } } // Append new query. di.ContinuousQueries = append(di.ContinuousQueries, ContinuousQueryInfo{ Name: name, Query: query, }) return nil }
// WritePoints writes across multiple local and remote data nodes according the consistency level. func (w *PointsWriter) WritePoints(database, retentionPolicy string, consistencyLevel models.ConsistencyLevel, points []models.Point) error { w.statMap.Add(statWriteReq, 1) w.statMap.Add(statPointWriteReq, int64(len(points))) if retentionPolicy == "" { db, err := w.MetaClient.Database(database) if err != nil { return err } else if db == nil { return influxdb.ErrDatabaseNotFound(database) } retentionPolicy = db.DefaultRetentionPolicy } shardMappings, err := w.MapShards(&WritePointsRequest{Database: database, RetentionPolicy: retentionPolicy, Points: points}) if err != nil { return err } // Write each shard in it's own goroutine and return as soon // as one fails. ch := make(chan error, len(shardMappings.Points)) for shardID, points := range shardMappings.Points { go func(shard *meta.ShardInfo, database, retentionPolicy string, points []models.Point) { ch <- w.writeToShard(shard, database, retentionPolicy, points) }(shardMappings.Shards[shardID], database, retentionPolicy, points) } // Send points to subscriptions if possible. ok := false // We need to lock just in case the channel is about to be nil'ed w.mu.RLock() select { case w.subPoints <- &WritePointsRequest{Database: database, RetentionPolicy: retentionPolicy, Points: points}: ok = true default: } w.mu.RUnlock() if ok { w.statMap.Add(statSubWriteOK, 1) } else { w.statMap.Add(statSubWriteDrop, 1) } for range shardMappings.Points { select { case <-w.closing: return ErrWriteFailed case err := <-ch: if err != nil { return err } } } return nil }
// RetentionPolicy returns the requested retention policy info. func (c *Client) RetentionPolicy(database, name string) (rpi *RetentionPolicyInfo, err error) { c.mu.RLock() data := c.cacheData.Clone() c.mu.RUnlock() db := data.Database(database) if db == nil { return nil, influxdb.ErrDatabaseNotFound(database) } return db.RetentionPolicy(name), nil }
// Database returns info for the requested database. func (c *Client) Database(name string) (*DatabaseInfo, error) { c.mu.RLock() data := c.cacheData.Clone() c.mu.RUnlock() for _, d := range data.Databases { if d.Name == name { return &d, nil } } return nil, influxdb.ErrDatabaseNotFound(name) }
// RetentionPolicy returns a retention policy for a database by name. func (data *Data) RetentionPolicy(database, name string) (*RetentionPolicyInfo, error) { di := data.Database(database) if di == nil { return nil, influxdb.ErrDatabaseNotFound(database) } for i := range di.RetentionPolicies { if di.RetentionPolicies[i].Name == name { return &di.RetentionPolicies[i], nil } } return nil, nil }
func (e *QueryExecutor) executeShowRetentionPoliciesStatement(q *influxql.ShowRetentionPoliciesStatement) (models.Rows, error) { di, err := e.MetaClient.Database(q.Database) if err != nil { return nil, err } else if di == nil { return nil, influxdb.ErrDatabaseNotFound(q.Database) } row := &models.Row{Columns: []string{"name", "duration", "shardGroupDuration", "replicaN", "default"}} for _, rpi := range di.RetentionPolicies { row.Values = append(row.Values, []interface{}{rpi.Name, rpi.Duration.String(), rpi.ShardGroupDuration.String(), rpi.ReplicaN, di.DefaultRetentionPolicy == rpi.Name}) } return []*models.Row{row}, nil }
// DropContinuousQuery removes a continuous query. func (data *Data) DropContinuousQuery(database, name string) error { di := data.Database(database) if di == nil { return influxdb.ErrDatabaseNotFound(database) } for i := range di.ContinuousQueries { if di.ContinuousQueries[i].Name == name { di.ContinuousQueries = append(di.ContinuousQueries[:i], di.ContinuousQueries[i+1:]...) return nil } } return ErrContinuousQueryNotFound }
// SetDefaultRetentionPolicy sets the default retention policy for a database. func (data *Data) SetDefaultRetentionPolicy(database, name string) error { // Find database and verify policy exists. di := data.Database(database) if di == nil { return influxdb.ErrDatabaseNotFound(database) } else if di.RetentionPolicy(name) == nil { return influxdb.ErrRetentionPolicyNotFound(name) } // Set default policy. di.DefaultRetentionPolicy = name return nil }
// UpdateRetentionPolicy updates an existing retention policy. func (data *Data) UpdateRetentionPolicy(database, name string, rpu *RetentionPolicyUpdate) error { // Find database. di := data.Database(database) if di == nil { return influxdb.ErrDatabaseNotFound(database) } // Find policy. rpi := di.RetentionPolicy(name) if rpi == nil { return influxdb.ErrRetentionPolicyNotFound(name) } // Ensure new policy doesn't match an existing policy. if rpu.Name != nil && *rpu.Name != name && di.RetentionPolicy(*rpu.Name) != nil { return ErrRetentionPolicyNameExists } // Enforce duration of at least MinRetentionPolicyDuration if rpu.Duration != nil && *rpu.Duration < MinRetentionPolicyDuration && *rpu.Duration != 0 { return ErrRetentionPolicyDurationTooLow } // Update fields. if rpu.Name != nil { rpi.Name = *rpu.Name } if rpu.Duration != nil { rpi.Duration = *rpu.Duration } if rpu.ReplicaN != nil { rpi.ReplicaN = *rpu.ReplicaN } if rpu.ShardGroupDuration != nil { rpi.ShardGroupDuration = *rpu.ShardGroupDuration } else { rpi.ShardGroupDuration = shardGroupDuration(rpi.Duration) } return nil }
// CreateRetentionPolicy creates a new retention policy on a database. // Returns an error if name is blank or if a database does not exist. func (data *Data) CreateRetentionPolicy(database string, rpi *RetentionPolicyInfo) error { // Validate retention policy. if rpi.Name == "" { return ErrRetentionPolicyNameRequired } else if rpi.ReplicaN < 1 { return ErrReplicationFactorTooLow } // Normalise ShardDuration before comparing to any existing // retention policies if rpi.ShardGroupDuration == 0 { rpi.ShardGroupDuration = shardGroupDuration(rpi.Duration) } // Find database. di := data.Database(database) if di == nil { return influxdb.ErrDatabaseNotFound(database) } else if rp := di.RetentionPolicy(rpi.Name); rp != nil { // RP with that name already exists. Make sure they're the same. if rp.ReplicaN != rpi.ReplicaN || rp.Duration != rpi.Duration || rp.ShardGroupDuration != rpi.ShardGroupDuration { return ErrRetentionPolicyExists } return nil } // Append copy of new policy. rp := RetentionPolicyInfo{ Name: rpi.Name, Duration: rpi.Duration, ReplicaN: rpi.ReplicaN, ShardGroupDuration: rpi.ShardGroupDuration, } di.RetentionPolicies = append(di.RetentionPolicies, rp) return nil }