// 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 } // 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 { return ErrRetentionPolicyExists } return nil } // Append new policy. di.RetentionPolicies = append(di.RetentionPolicies, RetentionPolicyInfo{ Name: rpi.Name, Duration: rpi.Duration, ShardGroupDuration: shardGroupDuration(rpi.Duration), ReplicaN: rpi.ReplicaN, }) return nil }
// Ensure that retrieving a policy from a non-existent database returns an error. func TestData_RetentionPolicy_ErrDatabaseNotFound(t *testing.T) { var data meta.Data expErr := influxdb.ErrDatabaseNotFound("db0") if _, err := data.RetentionPolicy("db0", "rp0"); err.Error() != expErr.Error() { t.Fatal(err) } }
// 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 } // Find database. di := data.Database(database) if di == nil { return influxdb.ErrDatabaseNotFound(database) } else if di.RetentionPolicy(rpi.Name) != nil { return ErrRetentionPolicyExists } // Append new policy. di.RetentionPolicies = append(di.RetentionPolicies, RetentionPolicyInfo{ Name: rpi.Name, Duration: rpi.Duration, ShardGroupDuration: shardGroupDuration(rpi.Duration), ReplicaN: rpi.ReplicaN, }) return nil }
// 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 }
// Ensure that creating a retention policy on a non-existent database returns an error. func TestData_CreateRetentionPolicy_ErrDatabaseNotFound(t *testing.T) { data := meta.Data{Nodes: []meta.NodeInfo{{ID: 1}}} expErr := influxdb.ErrDatabaseNotFound("db0") if err := data.CreateRetentionPolicy("db0", &meta.RetentionPolicyInfo{Name: "rp0", ReplicaN: 1}); err.Error() != expErr.Error() { t.Fatalf("unexpected error: %s", err) } }
// DropDatabase removes a database by name. func (data *Data) DropDatabase(name string) error { for i := range data.Databases { if data.Databases[i].Name == name { data.Databases = append(data.Databases[:i], data.Databases[i+1:]...) return nil } } return influxdb.ErrDatabaseNotFound(name) }
// WritePoints writes across multiple local and remote data nodes according the consistency level. func (w *PointsWriter) WritePoints(p *WritePointsRequest) error { w.statMap.Add(statWriteReq, 1) w.statMap.Add(statPointWriteReq, int64(len(p.Points))) if p.RetentionPolicy == "" { db, err := w.MetaStore.Database(p.Database) if err != nil { return err } else if db == nil { return influxdb.ErrDatabaseNotFound(p.Database) } p.RetentionPolicy = db.DefaultRetentionPolicy } shardMappings, err := w.MapShards(p) 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, p.Database, p.RetentionPolicy, p.ConsistencyLevel, points) }(shardMappings.Shards[shardID], p.Database, p.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 <- p: 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 }
// Ensure the store returns an error when dropping a database that doesn't exist. func TestStore_DropDatabase_ErrDatabaseNotFound(t *testing.T) { t.Parallel() s := MustOpenStore() defer s.Close() expErr := influxdb.ErrDatabaseNotFound("no_such_database") if err := s.DropDatabase("no_such_database"); err.Error() != expErr.Error() { t.Fatalf("unexpected error: %s", err) } }
// Ensure a SHOW RETENTION POLICIES statement can return an error if the database doesn't exist. func TestStatementExecutor_ExecuteStatement_ShowRetentionPolicies_ErrDatabaseNotFound(t *testing.T) { e := NewStatementExecutor() e.Store.DatabaseFn = func(name string) (*meta.DatabaseInfo, error) { return nil, nil } expErr := influxdb.ErrDatabaseNotFound("db0") if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW RETENTION POLICIES ON db0`)); res.Err.Error() != expErr.Error() { t.Fatalf("unexpected error: %s", res.Err) } }
// 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 }
// 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 }
func (e *StatementExecutor) executeShowRetentionPoliciesStatement(q *influxql.ShowRetentionPoliciesStatement) *influxql.Result { di, err := e.Store.Database(q.Database) if err != nil { return &influxql.Result{Err: err} } else if di == nil { return &influxql.Result{Err: influxdb.ErrDatabaseNotFound(q.Database)} } row := &models.Row{Columns: []string{"name", "duration", "replicaN", "default"}} for _, rpi := range di.RetentionPolicies { row.Values = append(row.Values, []interface{}{rpi.Name, rpi.Duration.String(), rpi.ReplicaN, di.DefaultRetentionPolicy == rpi.Name}) } return &influxql.Result{Series: []*models.Row{row}} }
// DropRetentionPolicy removes a retention policy from a database by name. func (data *Data) DropRetentionPolicy(database, name string) error { // Find database. di := data.Database(database) if di == nil { return influxdb.ErrDatabaseNotFound(database) } // Remove from list. for i := range di.RetentionPolicies { if di.RetentionPolicies[i].Name == name { di.RetentionPolicies = append(di.RetentionPolicies[:i], di.RetentionPolicies[i+1:]...) break } } 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 i := range di.ContinuousQueries { if di.ContinuousQueries[i].Name == name { return ErrContinuousQueryExists } } // Append new query. di.ContinuousQueries = append(di.ContinuousQueries, ContinuousQueryInfo{ Name: name, Query: query, }) return nil }
// DropRetentionPolicy removes a retention policy from a database by name. func (data *Data) DropRetentionPolicy(database, name string) error { // Find database. di := data.Database(database) if di == nil { return influxdb.ErrDatabaseNotFound(database) } // Prohibit dropping the default retention policy. if di.DefaultRetentionPolicy == name { return ErrRetentionPolicyDefault } // Remove from list. for i := range di.RetentionPolicies { if di.RetentionPolicies[i].Name == name { di.RetentionPolicies = append(di.RetentionPolicies[:i], di.RetentionPolicies[i+1:]...) return nil } } return influxdb.ErrRetentionPolicyNotFound(name) }
// WritePoints writes across multiple local and remote data nodes according the consistency level. func (w *PointsWriter) WritePoints(p *WritePointsRequest) error { w.statMap.Add(statWriteReq, 1) w.statMap.Add(statPointWriteReq, int64(len(p.Points))) if p.RetentionPolicy == "" { db, err := w.MetaStore.Database(p.Database) if err != nil { return err } else if db == nil { return influxdb.ErrDatabaseNotFound(p.Database) } p.RetentionPolicy = db.DefaultRetentionPolicy } shardMappings, err := w.MapShards(p) 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, p.Database, p.RetentionPolicy, p.ConsistencyLevel, points) }(shardMappings.Shards[shardID], p.Database, p.RetentionPolicy, points) } for range shardMappings.Points { select { case <-w.closing: return ErrWriteFailed case err := <-ch: if err != nil { return err } } } 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 rpi.ShardGroupDuration = shardGroupDuration(rpi.Duration) } if rpu.ReplicaN != nil { rpi.ReplicaN = *rpu.ReplicaN } return nil }