Merge pull request #1141 from influxdb/refactor_shard_space
Refactor ShardSpace to RetentionPolicypull/1143/head
commit
00fce7e56f
196
database.go
196
database.go
|
@ -3,7 +3,6 @@ package influxdb
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -12,17 +11,18 @@ import (
|
||||||
// "github.com/influxdb/influxdb/messaging"
|
// "github.com/influxdb/influxdb/messaging"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Database represents a collection of shard spaces.
|
// Database represents a collection of retention policies.
|
||||||
type Database struct {
|
type Database struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
server *Server
|
server *Server
|
||||||
name string
|
name string
|
||||||
|
|
||||||
users map[string]*DBUser // database users by name
|
users map[string]*DBUser // database users by name
|
||||||
spaces map[string]*ShardSpace // shard spaces by name
|
policies map[string]*RetentionPolicy // retention policies by name
|
||||||
shards map[uint64]*Shard // shards by id
|
shards map[uint64]*Shard // shards by id
|
||||||
series map[string]*Series // series by name
|
series map[string]*Series // series by name
|
||||||
|
|
||||||
|
defaultRetentionPolicy string
|
||||||
maxFieldID uint64 // largest field id in use
|
maxFieldID uint64 // largest field id in use
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ func newDatabase(s *Server) *Database {
|
||||||
return &Database{
|
return &Database{
|
||||||
server: s,
|
server: s,
|
||||||
users: make(map[string]*DBUser),
|
users: make(map[string]*DBUser),
|
||||||
spaces: make(map[string]*ShardSpace),
|
policies: make(map[string]*RetentionPolicy),
|
||||||
shards: make(map[uint64]*Shard),
|
shards: make(map[uint64]*Shard),
|
||||||
series: make(map[string]*Series),
|
series: make(map[string]*Series),
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,13 @@ func (db *Database) Name() string {
|
||||||
return db.name
|
return db.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultRetentionPolicy returns the retention policy that writes and queries will default to or nil if not set.
|
||||||
|
func (db *Database) DefaultRetentionPolicy() *RetentionPolicy {
|
||||||
|
db.mu.Lock()
|
||||||
|
defer db.mu.Unlock()
|
||||||
|
return db.policies[db.defaultRetentionPolicy]
|
||||||
|
}
|
||||||
|
|
||||||
// User returns a database user by name.
|
// User returns a database user by name.
|
||||||
func (db *Database) User(name string) *DBUser {
|
func (db *Database) User(name string) *DBUser {
|
||||||
db.mu.Lock()
|
db.mu.Lock()
|
||||||
|
@ -180,59 +187,40 @@ func (db *Database) applyChangePassword(username, newPassword string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShardSpace returns a shard space by name.
|
// RetentionPolicy returns a retention policy by name.
|
||||||
func (db *Database) ShardSpace(name string) *ShardSpace {
|
func (db *Database) RetentionPolicy(name string) *RetentionPolicy {
|
||||||
db.mu.Lock()
|
db.mu.Lock()
|
||||||
defer db.mu.Unlock()
|
defer db.mu.Unlock()
|
||||||
return db.spaces[name]
|
return db.policies[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
// shardSpaceBySeries returns a shard space that matches a series name.
|
// CreateRetentionPolicy creates a retention policy in the database.
|
||||||
func (db *Database) shardSpaceBySeries(name string) *ShardSpace {
|
func (db *Database) CreateRetentionPolicy(ss *RetentionPolicy) error {
|
||||||
for _, ss := range db.spaces {
|
c := &createRetentionPolicyCommand{
|
||||||
if ss.Regex.MatchString(name) {
|
|
||||||
return ss
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateShardSpace creates a shard space in the database.
|
|
||||||
func (db *Database) CreateShardSpace(ss *ShardSpace) error {
|
|
||||||
c := &createShardSpaceCommand{
|
|
||||||
Database: db.Name(),
|
Database: db.Name(),
|
||||||
Name: ss.Name,
|
Name: ss.Name,
|
||||||
Retention: ss.Retention,
|
|
||||||
Duration: ss.Duration,
|
Duration: ss.Duration,
|
||||||
ReplicaN: ss.ReplicaN,
|
ReplicaN: ss.ReplicaN,
|
||||||
SplitN: ss.SplitN,
|
SplitN: ss.SplitN,
|
||||||
}
|
}
|
||||||
if ss.Regex != nil {
|
_, err := db.server.broadcast(createRetentionPolicyMessageType, c)
|
||||||
c.Regex = ss.Regex.String()
|
|
||||||
}
|
|
||||||
_, err := db.server.broadcast(createShardSpaceMessageType, c)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) applyCreateShardSpace(name, regex string, retention, duration time.Duration, replicaN, splitN uint32) error {
|
func (db *Database) applyCreateRetentionPolicy(name string, duration time.Duration, replicaN, splitN uint32) error {
|
||||||
db.mu.Lock()
|
db.mu.Lock()
|
||||||
defer db.mu.Unlock()
|
defer db.mu.Unlock()
|
||||||
|
|
||||||
// Validate shard space.
|
// Validate retention policy.
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return ErrShardSpaceNameRequired
|
return ErrRetentionPolicyNameRequired
|
||||||
} else if db.spaces[name] != nil {
|
} else if db.policies[name] != nil {
|
||||||
return ErrShardSpaceExists
|
return ErrRetentionPolicyExists
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile regex.
|
|
||||||
re := regexp.MustCompile(regex)
|
|
||||||
|
|
||||||
// Add space to the database.
|
// Add space to the database.
|
||||||
db.spaces[name] = &ShardSpace{
|
db.policies[name] = &RetentionPolicy{
|
||||||
Name: name,
|
Name: name,
|
||||||
Regex: re,
|
|
||||||
Retention: retention,
|
|
||||||
Duration: duration,
|
Duration: duration,
|
||||||
ReplicaN: replicaN,
|
ReplicaN: replicaN,
|
||||||
SplitN: splitN,
|
SplitN: splitN,
|
||||||
|
@ -241,32 +229,52 @@ func (db *Database) applyCreateShardSpace(name, regex string, retention, duratio
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteShardSpace removes a shard space from the database.
|
// DeleteRetentionPolicy removes a retention policy from the database.
|
||||||
func (db *Database) DeleteShardSpace(name string) error {
|
func (db *Database) DeleteRetentionPolicy(name string) error {
|
||||||
c := &deleteShardSpaceCommand{Database: db.Name(), Name: name}
|
c := &deleteRetentionPolicyCommand{Database: db.Name(), Name: name}
|
||||||
_, err := db.server.broadcast(deleteShardSpaceMessageType, c)
|
_, err := db.server.broadcast(deleteRetentionPolicyMessageType, c)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) applyDeleteShardSpace(name string) error {
|
func (db *Database) applyDeleteRetentionPolicy(name string) error {
|
||||||
db.mu.Lock()
|
db.mu.Lock()
|
||||||
defer db.mu.Unlock()
|
defer db.mu.Unlock()
|
||||||
|
|
||||||
// Validate shard space.
|
// Validate retention policy.
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return ErrShardSpaceNameRequired
|
return ErrRetentionPolicyNameRequired
|
||||||
} else if db.spaces[name] == nil {
|
} else if db.policies[name] == nil {
|
||||||
return ErrShardSpaceNotFound
|
return ErrRetentionPolicyNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove shard space.
|
// Remove retention policy.
|
||||||
delete(db.spaces, name)
|
delete(db.policies, name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaultRetentionPolicy sets the default policy to write data into and query from on a database.
|
||||||
|
func (db *Database) SetDefaultRetentionPolicy(name string) error {
|
||||||
|
c := &setDefaultRetentionPolicyCommand{Database: db.Name(), Name: name}
|
||||||
|
_, err := db.server.broadcast(setDefaultRetentionPolicyMessageType, c)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) applySetDefaultRetentionPolicy(name string) error {
|
||||||
|
db.mu.Lock()
|
||||||
|
defer db.mu.Unlock()
|
||||||
|
|
||||||
|
// Check the retention policy exists
|
||||||
|
if db.policies[name] == nil {
|
||||||
|
return ErrRetentionPolicyNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
db.defaultRetentionPolicy = name
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// shard returns a shard by id.
|
// shard returns a shard by id.
|
||||||
func (db *Database) shard(id uint64) *Shard {
|
func (db *Database) shard(id uint64) *Shard {
|
||||||
for _, ss := range db.spaces {
|
for _, ss := range db.policies {
|
||||||
for _, s := range ss.Shards {
|
for _, s := range ss.Shards {
|
||||||
if s.ID == id {
|
if s.ID == id {
|
||||||
return s
|
return s
|
||||||
|
@ -276,21 +284,21 @@ func (db *Database) shard(id uint64) *Shard {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateShardIfNotExists creates a shard for a shard space for a given timestamp.
|
// CreateShardIfNotExists creates a shard for a retention policy for a given timestamp.
|
||||||
func (db *Database) CreateShardIfNotExists(space string, timestamp time.Time) error {
|
func (db *Database) CreateShardIfNotExists(space string, timestamp time.Time) error {
|
||||||
c := &createShardIfNotExistsSpaceCommand{Database: db.name, Space: space, Timestamp: timestamp}
|
c := &createShardIfNotExistsSpaceCommand{Database: db.name, Space: space, Timestamp: timestamp}
|
||||||
_, err := db.server.broadcast(createShardIfNotExistsMessageType, c)
|
_, err := db.server.broadcast(createShardIfNotExistsMessageType, c)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) applyCreateShardIfNotExists(id uint64, space string, timestamp time.Time) (error, bool) {
|
func (db *Database) applyCreateShardIfNotExists(id uint64, policy string, timestamp time.Time) (error, bool) {
|
||||||
db.mu.Lock()
|
db.mu.Lock()
|
||||||
defer db.mu.Unlock()
|
defer db.mu.Unlock()
|
||||||
|
|
||||||
// Validate shard space.
|
// Validate retention policy.
|
||||||
ss := db.spaces[space]
|
ss := db.policies[policy]
|
||||||
if ss == nil {
|
if ss == nil {
|
||||||
return ErrShardSpaceNotFound, false
|
return ErrRetentionPolicyNotFound, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we can match to an existing shard date range then just ignore request.
|
// If we can match to an existing shard date range then just ignore request.
|
||||||
|
@ -311,7 +319,7 @@ func (db *Database) applyCreateShardIfNotExists(id uint64, space string, timesta
|
||||||
panic("unable to open shard: " + err.Error())
|
panic("unable to open shard: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append to shard space.
|
// Append to retention policy.
|
||||||
ss.Shards = append(ss.Shards, s)
|
ss.Shards = append(ss.Shards, s)
|
||||||
|
|
||||||
return nil, true
|
return nil, true
|
||||||
|
@ -322,15 +330,15 @@ func (db *Database) WriteSeries(name string, tags map[string]string, timestamp t
|
||||||
panic("not yet implemented: Database.WriteSeries()")
|
panic("not yet implemented: Database.WriteSeries()")
|
||||||
|
|
||||||
/* TEMPORARILY REMOVED FOR PROTOBUFS.
|
/* TEMPORARILY REMOVED FOR PROTOBUFS.
|
||||||
// Find shard space matching the series and split points by shard.
|
// Find retention policy matching the series and split points by shard.
|
||||||
db.mu.Lock()
|
db.mu.Lock()
|
||||||
name := db.name
|
name := db.name
|
||||||
space := db.shardSpaceBySeries(series.GetName())
|
space := db.retentionPolicyBySeries(series.GetName())
|
||||||
db.mu.Unlock()
|
db.mu.Unlock()
|
||||||
|
|
||||||
// Ensure there is a space available.
|
// Ensure there is a space available.
|
||||||
if space == nil {
|
if space == nil {
|
||||||
return ErrShardSpaceNotFound
|
return ErrRetentionPolicyNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group points by shard.
|
// Group points by shard.
|
||||||
|
@ -458,12 +466,13 @@ func (db *Database) MarshalJSON() ([]byte, error) {
|
||||||
// Copy over properties to intermediate type.
|
// Copy over properties to intermediate type.
|
||||||
var o databaseJSON
|
var o databaseJSON
|
||||||
o.Name = db.name
|
o.Name = db.name
|
||||||
|
o.DefaultRetentionPolicy = db.defaultRetentionPolicy
|
||||||
o.MaxFieldID = db.maxFieldID
|
o.MaxFieldID = db.maxFieldID
|
||||||
for _, u := range db.users {
|
for _, u := range db.users {
|
||||||
o.Users = append(o.Users, u)
|
o.Users = append(o.Users, u)
|
||||||
}
|
}
|
||||||
for _, ss := range db.spaces {
|
for _, ss := range db.policies {
|
||||||
o.Spaces = append(o.Spaces, ss)
|
o.Policies = append(o.Policies, ss)
|
||||||
}
|
}
|
||||||
for _, s := range db.shards {
|
for _, s := range db.shards {
|
||||||
o.Shards = append(o.Shards, s)
|
o.Shards = append(o.Shards, s)
|
||||||
|
@ -484,6 +493,7 @@ func (db *Database) UnmarshalJSON(data []byte) error {
|
||||||
|
|
||||||
// Copy over properties from intermediate type.
|
// Copy over properties from intermediate type.
|
||||||
db.name = o.Name
|
db.name = o.Name
|
||||||
|
db.defaultRetentionPolicy = o.DefaultRetentionPolicy
|
||||||
db.maxFieldID = o.MaxFieldID
|
db.maxFieldID = o.MaxFieldID
|
||||||
|
|
||||||
// Copy users.
|
// Copy users.
|
||||||
|
@ -492,10 +502,10 @@ func (db *Database) UnmarshalJSON(data []byte) error {
|
||||||
db.users[u.Name] = u
|
db.users[u.Name] = u
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy shard spaces.
|
// Copy shard policies.
|
||||||
db.spaces = make(map[string]*ShardSpace)
|
db.policies = make(map[string]*RetentionPolicy)
|
||||||
for _, ss := range o.Spaces {
|
for _, ss := range o.Policies {
|
||||||
db.spaces[ss.Name] = ss
|
db.policies[ss.Name] = ss
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy shards.
|
// Copy shards.
|
||||||
|
@ -516,9 +526,10 @@ func (db *Database) UnmarshalJSON(data []byte) error {
|
||||||
// databaseJSON represents the JSON-serialization format for a database.
|
// databaseJSON represents the JSON-serialization format for a database.
|
||||||
type databaseJSON struct {
|
type databaseJSON struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
DefaultRetentionPolicy string `json:"defaultRetentionPolicy,omitempty"`
|
||||||
MaxFieldID uint64 `json:"maxFieldID,omitempty"`
|
MaxFieldID uint64 `json:"maxFieldID,omitempty"`
|
||||||
Users []*DBUser `json:"users,omitempty"`
|
Users []*DBUser `json:"users,omitempty"`
|
||||||
Spaces []*ShardSpace `json:"spaces,omitempty"`
|
Policies []*RetentionPolicy `json:"policies,omitempty"`
|
||||||
Shards []*Shard `json:"shards,omitempty"`
|
Shards []*Shard `json:"shards,omitempty"`
|
||||||
Series []*Series `json:"series,omitempty"`
|
Series []*Series `json:"series,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -530,15 +541,12 @@ func (p databases) Len() int { return len(p) }
|
||||||
func (p databases) Less(i, j int) bool { return p[i].name < p[j].name }
|
func (p databases) Less(i, j int) bool { return p[i].name < p[j].name }
|
||||||
func (p databases) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
func (p databases) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||||
|
|
||||||
// ShardSpace represents a policy for creating new shards in a database.
|
// RetentionPolicy represents a policy for creating new shards in a database and how long they're kept around for.
|
||||||
type ShardSpace struct {
|
type RetentionPolicy struct {
|
||||||
// Unique name within database. Required.
|
// Unique name within database. Required.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Expression used to match against series. Optional. Defaults to /.*/.
|
// Length of time to keep data around
|
||||||
Regex *regexp.Regexp
|
|
||||||
|
|
||||||
Retention time.Duration
|
|
||||||
Duration time.Duration
|
Duration time.Duration
|
||||||
|
|
||||||
ReplicaN uint32
|
ReplicaN uint32
|
||||||
|
@ -547,21 +555,19 @@ type ShardSpace struct {
|
||||||
Shards []*Shard
|
Shards []*Shard
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewShardSpace returns a new instance of ShardSpace with defaults set.
|
// NewRetentionPolicy returns a new instance of RetentionPolicy with defaults set.
|
||||||
func NewShardSpace() *ShardSpace {
|
func NewRetentionPolicy() *RetentionPolicy {
|
||||||
return &ShardSpace{
|
return &RetentionPolicy{
|
||||||
Regex: regexp.MustCompile(`.*`),
|
|
||||||
ReplicaN: DefaultReplicaN,
|
ReplicaN: DefaultReplicaN,
|
||||||
SplitN: DefaultSplitN,
|
SplitN: DefaultSplitN,
|
||||||
Retention: DefaultShardRetention,
|
Duration: DefaultShardRetention,
|
||||||
Duration: DefaultShardDuration,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// SplitPoints groups a set of points by shard id.
|
// SplitPoints groups a set of points by shard id.
|
||||||
// Also returns a list of timestamps that did not match an existing shard.
|
// Also returns a list of timestamps that did not match an existing shard.
|
||||||
func (ss *ShardSpace) Split(a []*protocol.Point) (points map[uint64][]*protocol.Point, unassigned []*protocol.Point) {
|
func (ss *RetentionPolicy) Split(a []*protocol.Point) (points map[uint64][]*protocol.Point, unassigned []*protocol.Point) {
|
||||||
points = make(map[uint64][]*protocol.Point)
|
points = make(map[uint64][]*protocol.Point)
|
||||||
for _, p := range a {
|
for _, p := range a {
|
||||||
if s := ss.ShardByTimestamp(time.Unix(0, p.GetTimestamp())); s != nil {
|
if s := ss.ShardByTimestamp(time.Unix(0, p.GetTimestamp())); s != nil {
|
||||||
|
@ -576,7 +582,7 @@ func (ss *ShardSpace) Split(a []*protocol.Point) (points map[uint64][]*protocol.
|
||||||
|
|
||||||
// ShardByTimestamp returns the shard in the space that owns a given timestamp.
|
// ShardByTimestamp returns the shard in the space that owns a given timestamp.
|
||||||
// Returns nil if the shard does not exist.
|
// Returns nil if the shard does not exist.
|
||||||
func (ss *ShardSpace) ShardByTimestamp(timestamp time.Time) *Shard {
|
func (ss *RetentionPolicy) ShardByTimestamp(timestamp time.Time) *Shard {
|
||||||
for _, s := range ss.Shards {
|
for _, s := range ss.Shards {
|
||||||
if timeBetween(timestamp, s.StartTime, s.EndTime) {
|
if timeBetween(timestamp, s.StartTime, s.EndTime) {
|
||||||
return s
|
return s
|
||||||
|
@ -585,22 +591,20 @@ func (ss *ShardSpace) ShardByTimestamp(timestamp time.Time) *Shard {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON encodes a shard space to a JSON-encoded byte slice.
|
// MarshalJSON encodes a retention policy to a JSON-encoded byte slice.
|
||||||
func (s *ShardSpace) MarshalJSON() ([]byte, error) {
|
func (s *RetentionPolicy) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(&shardSpaceJSON{
|
return json.Marshal(&retentionPolicyJSON{
|
||||||
Name: s.Name,
|
Name: s.Name,
|
||||||
Regex: s.Regex.String(),
|
|
||||||
Retention: s.Retention,
|
|
||||||
Duration: s.Duration,
|
Duration: s.Duration,
|
||||||
ReplicaN: s.ReplicaN,
|
ReplicaN: s.ReplicaN,
|
||||||
SplitN: s.SplitN,
|
SplitN: s.SplitN,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON decodes a JSON-encoded byte slice to a shard space.
|
// UnmarshalJSON decodes a JSON-encoded byte slice to a retention policy.
|
||||||
func (s *ShardSpace) UnmarshalJSON(data []byte) error {
|
func (s *RetentionPolicy) UnmarshalJSON(data []byte) error {
|
||||||
// Decode into intermediate type.
|
// Decode into intermediate type.
|
||||||
var o shardSpaceJSON
|
var o retentionPolicyJSON
|
||||||
if err := json.Unmarshal(data, &o); err != nil {
|
if err := json.Unmarshal(data, &o); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -609,34 +613,26 @@ func (s *ShardSpace) UnmarshalJSON(data []byte) error {
|
||||||
s.Name = o.Name
|
s.Name = o.Name
|
||||||
s.ReplicaN = o.ReplicaN
|
s.ReplicaN = o.ReplicaN
|
||||||
s.SplitN = o.SplitN
|
s.SplitN = o.SplitN
|
||||||
s.Retention = o.Retention
|
|
||||||
s.Duration = o.Duration
|
s.Duration = o.Duration
|
||||||
s.Shards = o.Shards
|
s.Shards = o.Shards
|
||||||
|
|
||||||
s.Regex, _ = regexp.Compile(o.Regex)
|
|
||||||
if s.Regex == nil {
|
|
||||||
s.Regex = regexp.MustCompile(`.*`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// shardSpaceJSON represents an intermediate struct for JSON marshaling.
|
// retentionPolicyJSON represents an intermediate struct for JSON marshaling.
|
||||||
type shardSpaceJSON struct {
|
type retentionPolicyJSON struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Regex string `json:"regex,omitempty"`
|
|
||||||
ReplicaN uint32 `json:"replicaN,omitempty"`
|
ReplicaN uint32 `json:"replicaN,omitempty"`
|
||||||
SplitN uint32 `json:"splitN,omitempty"`
|
SplitN uint32 `json:"splitN,omitempty"`
|
||||||
Retention time.Duration `json:"retention,omitempty"`
|
|
||||||
Duration time.Duration `json:"duration,omitempty"`
|
Duration time.Duration `json:"duration,omitempty"`
|
||||||
Shards []*Shard `json:"shards,omitempty"`
|
Shards []*Shard `json:"shards,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShardSpaces represents a list of shard spaces.
|
// RetentionPolicys represents a list of shard policies.
|
||||||
type ShardSpaces []*ShardSpace
|
type RetentionPolicys []*RetentionPolicy
|
||||||
|
|
||||||
// Shards returns a list of all shards for all spaces.
|
// Shards returns a list of all shards for all policies.
|
||||||
func (a ShardSpaces) Shards() []*Shard {
|
func (a RetentionPolicys) Shards() []*Shard {
|
||||||
var shards []*Shard
|
var shards []*Shard
|
||||||
for _, ss := range a {
|
for _, ss := range a {
|
||||||
shards = append(shards, ss.Shards...)
|
shards = append(shards, ss.Shards...)
|
||||||
|
|
137
database_test.go
137
database_test.go
|
@ -2,7 +2,6 @@ package influxdb_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -216,8 +215,8 @@ func TestDatabase_Users(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the database can create a new shard space.
|
// Ensure the database can create a new retention policy.
|
||||||
func TestDatabase_CreateShardSpace(t *testing.T) {
|
func TestDatabase_CreateRetentionPolicy(t *testing.T) {
|
||||||
s := OpenServer(NewMessagingClient())
|
s := OpenServer(NewMessagingClient())
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
|
@ -226,30 +225,28 @@ func TestDatabase_CreateShardSpace(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a shard space on the database.
|
// Create a retention policy on the database.
|
||||||
ss := &influxdb.ShardSpace{
|
rp := &influxdb.RetentionPolicy{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Regex: regexp.MustCompile(`myseries`),
|
|
||||||
Duration: time.Hour,
|
Duration: time.Hour,
|
||||||
Retention: time.Minute,
|
|
||||||
ReplicaN: 2,
|
ReplicaN: 2,
|
||||||
SplitN: 3,
|
SplitN: 3,
|
||||||
}
|
}
|
||||||
if err := s.Database("foo").CreateShardSpace(ss); err != nil {
|
if err := s.Database("foo").CreateRetentionPolicy(rp); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
s.Restart()
|
s.Restart()
|
||||||
|
|
||||||
// Verify that the user exists.
|
// Verify that the policy exists.
|
||||||
if o := s.Database("foo").ShardSpace("bar"); o == nil {
|
if o := s.Database("foo").RetentionPolicy("bar"); o == nil {
|
||||||
t.Fatalf("shard space not found")
|
t.Fatalf("retention policy not found")
|
||||||
} else if !reflect.DeepEqual(ss, o) {
|
} else if !reflect.DeepEqual(rp, o) {
|
||||||
t.Fatalf("shard space mismatch: %#v", o)
|
t.Fatalf("retention policy mismatch: %#v", o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the server returns an error when creating a shard space after db is dropped.
|
// Ensure the server returns an error when creating a retention policy after db is dropped.
|
||||||
func TestDatabase_CreateShardSpace_ErrDatabaseNotFound(t *testing.T) {
|
func TestDatabase_CreateRetentionPolicy_ErrDatabaseNotFound(t *testing.T) {
|
||||||
s := OpenServer(NewMessagingClient())
|
s := OpenServer(NewMessagingClient())
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
|
@ -258,62 +255,62 @@ func TestDatabase_CreateShardSpace_ErrDatabaseNotFound(t *testing.T) {
|
||||||
db := s.Database("foo")
|
db := s.Database("foo")
|
||||||
s.DeleteDatabase("foo")
|
s.DeleteDatabase("foo")
|
||||||
|
|
||||||
// Create a shard space on the database.
|
// Create a retention policy on the database.
|
||||||
if err := db.CreateShardSpace(&influxdb.ShardSpace{Name: "bar"}); err != influxdb.ErrDatabaseNotFound {
|
if err := db.CreateRetentionPolicy(&influxdb.RetentionPolicy{Name: "bar"}); err != influxdb.ErrDatabaseNotFound {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the server returns an error when creating a shard space without a name.
|
// Ensure the server returns an error when creating a retention policy without a name.
|
||||||
func TestDatabase_CreateShardSpace_ErrShardSpaceNameRequired(t *testing.T) {
|
func TestDatabase_CreateRetentionPolicy_ErrRetentionPolicyNameRequired(t *testing.T) {
|
||||||
s := OpenServer(NewMessagingClient())
|
s := OpenServer(NewMessagingClient())
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
s.CreateDatabase("foo")
|
s.CreateDatabase("foo")
|
||||||
if err := s.Database("foo").CreateShardSpace(&influxdb.ShardSpace{Name: ""}); err != influxdb.ErrShardSpaceNameRequired {
|
if err := s.Database("foo").CreateRetentionPolicy(&influxdb.RetentionPolicy{Name: ""}); err != influxdb.ErrRetentionPolicyNameRequired {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the server returns an error when creating a duplicate shard space.
|
// Ensure the server returns an error when creating a duplicate retention policy.
|
||||||
func TestDatabase_CreateShardSpace_ErrShardSpaceExists(t *testing.T) {
|
func TestDatabase_CreateRetentionPolicy_ErrRetentionPolicyExists(t *testing.T) {
|
||||||
s := OpenServer(NewMessagingClient())
|
s := OpenServer(NewMessagingClient())
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
s.CreateDatabase("foo")
|
s.CreateDatabase("foo")
|
||||||
s.Database("foo").CreateShardSpace(&influxdb.ShardSpace{Name: "bar"})
|
s.Database("foo").CreateRetentionPolicy(&influxdb.RetentionPolicy{Name: "bar"})
|
||||||
if err := s.Database("foo").CreateShardSpace(&influxdb.ShardSpace{Name: "bar"}); err != influxdb.ErrShardSpaceExists {
|
if err := s.Database("foo").CreateRetentionPolicy(&influxdb.RetentionPolicy{Name: "bar"}); err != influxdb.ErrRetentionPolicyExists {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the server can delete an existing shard space.
|
// Ensure the server can delete an existing retention policy.
|
||||||
func TestDatabase_DeleteShardSpace(t *testing.T) {
|
func TestDatabase_DeleteRetentionPolicy(t *testing.T) {
|
||||||
s := OpenServer(NewMessagingClient())
|
s := OpenServer(NewMessagingClient())
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
// Create a database and shard space.
|
// Create a database and retention policy.
|
||||||
s.CreateDatabase("foo")
|
s.CreateDatabase("foo")
|
||||||
db := s.Database("foo")
|
db := s.Database("foo")
|
||||||
if err := db.CreateShardSpace(&influxdb.ShardSpace{Name: "bar"}); err != nil {
|
if err := db.CreateRetentionPolicy(&influxdb.RetentionPolicy{Name: "bar"}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if db.ShardSpace("bar") == nil {
|
} else if db.RetentionPolicy("bar") == nil {
|
||||||
t.Fatal("shard space not created")
|
t.Fatal("retention policy not created")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove shard space from database.
|
// Remove retention policy from database.
|
||||||
if err := db.DeleteShardSpace("bar"); err != nil {
|
if err := db.DeleteRetentionPolicy("bar"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if db.ShardSpace("bar") != nil {
|
} else if db.RetentionPolicy("bar") != nil {
|
||||||
t.Fatal("shard space not deleted")
|
t.Fatal("retention policy not deleted")
|
||||||
}
|
}
|
||||||
s.Restart()
|
s.Restart()
|
||||||
|
|
||||||
if s.Database("foo").ShardSpace("bar") != nil {
|
if s.Database("foo").RetentionPolicy("bar") != nil {
|
||||||
t.Fatal("shard space not deleted after restart")
|
t.Fatal("retention policy not deleted after restart")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the server returns an error when deleting a shard space after db is dropped.
|
// Ensure the server returns an error when deleting a retention policy after db is dropped.
|
||||||
func TestDatabase_DeleteShardSpace_ErrDatabaseNotFound(t *testing.T) {
|
func TestDatabase_DeleteRetentionPolicy_ErrDatabaseNotFound(t *testing.T) {
|
||||||
s := OpenServer(NewMessagingClient())
|
s := OpenServer(NewMessagingClient())
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
|
@ -322,28 +319,74 @@ func TestDatabase_DeleteShardSpace_ErrDatabaseNotFound(t *testing.T) {
|
||||||
db := s.Database("foo")
|
db := s.Database("foo")
|
||||||
s.DeleteDatabase("foo")
|
s.DeleteDatabase("foo")
|
||||||
|
|
||||||
// Delete shard space on the database.
|
// Delete retention policy on the database.
|
||||||
if err := db.DeleteShardSpace("bar"); err != influxdb.ErrDatabaseNotFound {
|
if err := db.DeleteRetentionPolicy("bar"); err != influxdb.ErrDatabaseNotFound {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the server returns an error when deleting a shard space without a name.
|
// Ensure the server returns an error when deleting a retention policy without a name.
|
||||||
func TestDatabase_DeleteShardSpace_ErrShardSpaceNameRequired(t *testing.T) {
|
func TestDatabase_DeleteRetentionPolicy_ErrRetentionPolicyNameRequired(t *testing.T) {
|
||||||
s := OpenServer(NewMessagingClient())
|
s := OpenServer(NewMessagingClient())
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
s.CreateDatabase("foo")
|
s.CreateDatabase("foo")
|
||||||
if err := s.Database("foo").DeleteShardSpace(""); err != influxdb.ErrShardSpaceNameRequired {
|
if err := s.Database("foo").DeleteRetentionPolicy(""); err != influxdb.ErrRetentionPolicyNameRequired {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the server returns an error when deleting a non-existent shard space.
|
// Ensure the server returns an error when deleting a non-existent retention policy.
|
||||||
func TestDatabase_DeleteShardSpace_ErrShardSpaceNotFound(t *testing.T) {
|
func TestDatabase_DeleteRetentionPolicy_ErrRetentionPolicyNotFound(t *testing.T) {
|
||||||
s := OpenServer(NewMessagingClient())
|
s := OpenServer(NewMessagingClient())
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
s.CreateDatabase("foo")
|
s.CreateDatabase("foo")
|
||||||
if err := s.Database("foo").DeleteShardSpace("no_such_space"); err != influxdb.ErrShardSpaceNotFound {
|
if err := s.Database("foo").DeleteRetentionPolicy("no_such_policy"); err != influxdb.ErrRetentionPolicyNotFound {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the server can set the default retention policy
|
||||||
|
func TestDatabase_SetDefaultRetentionPolicy(t *testing.T) {
|
||||||
|
s := OpenServer(NewMessagingClient())
|
||||||
|
defer s.Close()
|
||||||
|
s.CreateDatabase("foo")
|
||||||
|
db := s.Database("foo")
|
||||||
|
|
||||||
|
rp := &influxdb.RetentionPolicy{Name: "bar"}
|
||||||
|
if err := db.CreateRetentionPolicy(rp); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if db.RetentionPolicy("bar") == nil {
|
||||||
|
t.Fatal("retention policy not created")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set bar as default
|
||||||
|
if err := db.SetDefaultRetentionPolicy("bar"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
o := db.DefaultRetentionPolicy()
|
||||||
|
if o == nil {
|
||||||
|
t.Fatal("default policy not set")
|
||||||
|
} else if !reflect.DeepEqual(rp, o) {
|
||||||
|
t.Fatalf("retention policy mismatch: %#v", o)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Restart()
|
||||||
|
|
||||||
|
o = s.Database("foo").DefaultRetentionPolicy()
|
||||||
|
if o == nil {
|
||||||
|
t.Fatal("default policy not kept after restart")
|
||||||
|
} else if !reflect.DeepEqual(rp, o) {
|
||||||
|
t.Fatalf("retention policy mismatch after restart: %#v", o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the server returns an error when setting the deafult retention policy to a non-existant one.
|
||||||
|
func TestDatabase_SetDefaultRetentionPolicy_ErrRetentionPolicyNotFound(t *testing.T) {
|
||||||
|
s := OpenServer(NewMessagingClient())
|
||||||
|
defer s.Close()
|
||||||
|
s.CreateDatabase("foo")
|
||||||
|
if err := s.Database("foo").SetDefaultRetentionPolicy("no_such_policy"); err != influxdb.ErrRetentionPolicyNotFound {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -357,7 +400,7 @@ func TestDatabase_WriteSeries(t *testing.T) {
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
s.CreateDatabase("foo")
|
s.CreateDatabase("foo")
|
||||||
db := s.Database("foo")
|
db := s.Database("foo")
|
||||||
db.CreateShardSpace(&influxdb.ShardSpace{Name: "myspace", Duration: 1 * time.Hour})
|
db.CreateRetentionPolicys(&influxdb.RetentionPolicy{Name: "myspace", Duration: 1 * time.Hour})
|
||||||
db.CreateUser("susy", "pass", nil)
|
db.CreateUser("susy", "pass", nil)
|
||||||
|
|
||||||
// Write series with one point to the database.
|
// Write series with one point to the database.
|
||||||
|
|
68
handler.go
68
handler.go
|
@ -57,15 +57,15 @@ func NewHandler(s *Server) *Handler {
|
||||||
h.mux.Get("/interfaces", http.HandlerFunc(h.serveInterfaces))
|
h.mux.Get("/interfaces", http.HandlerFunc(h.serveInterfaces))
|
||||||
|
|
||||||
// Shard routes.
|
// Shard routes.
|
||||||
h.mux.Get("/cluster/shards", http.HandlerFunc(h.serveShards))
|
h.mux.Get("/db/:db/shards", http.HandlerFunc(h.serveShards))
|
||||||
h.mux.Post("/cluster/shards", http.HandlerFunc(h.serveCreateShard))
|
h.mux.Del("/db/:db/shards/:id", http.HandlerFunc(h.serveDeleteShard))
|
||||||
h.mux.Del("/cluster/shards/:id", http.HandlerFunc(h.serveDeleteShard))
|
|
||||||
|
|
||||||
// Shard space routes.
|
// retention policy routes.
|
||||||
h.mux.Get("/cluster/shard_spaces", http.HandlerFunc(h.serveShardSpaces))
|
h.mux.Get("/db/:db/retention_policies", http.HandlerFunc(h.serveRetentionPolicys))
|
||||||
h.mux.Post("/cluster/shard_spaces/:db", http.HandlerFunc(h.serveCreateShardSpace))
|
h.mux.Get("/db/:db/retention_policies/:name/shards", http.HandlerFunc(h.serveShardsByRetentionPolicy))
|
||||||
h.mux.Post("/cluster/shard_spaces/:db/:name", http.HandlerFunc(h.serveUpdateShardSpace))
|
h.mux.Post("/db/:db/retention_policies", http.HandlerFunc(h.serveCreateRetentionPolicy))
|
||||||
h.mux.Del("/cluster/shard_spaces/:db/:name", http.HandlerFunc(h.serveDeleteShardSpace))
|
h.mux.Post("/db/:db/retention_policies/:name", http.HandlerFunc(h.serveUpdateRetentionPolicy))
|
||||||
|
h.mux.Del("/db/:db/retention_policies/:name", http.HandlerFunc(h.serveDeleteRetentionPolicy))
|
||||||
|
|
||||||
// Cluster config endpoints
|
// Cluster config endpoints
|
||||||
h.mux.Get("/cluster/servers", http.HandlerFunc(h.serveServers))
|
h.mux.Get("/cluster/servers", http.HandlerFunc(h.serveServers))
|
||||||
|
@ -277,23 +277,23 @@ func (h *Handler) serveInterfaces(w http.ResponseWriter, r *http.Request) {}
|
||||||
// serveShards returns a list of shards.
|
// serveShards returns a list of shards.
|
||||||
func (h *Handler) serveShards(w http.ResponseWriter, r *http.Request) {}
|
func (h *Handler) serveShards(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
// serveCreateShard creates a new shard.
|
// serveShardsByRetentionPolicy returns a list of shards for a given retention policy.
|
||||||
func (h *Handler) serveCreateShard(w http.ResponseWriter, r *http.Request) {}
|
func (h *Handler) serveShardsByRetentionPolicy(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
// serveDeleteShard removes an existing shard.
|
// serveDeleteShard removes an existing shard.
|
||||||
func (h *Handler) serveDeleteShard(w http.ResponseWriter, r *http.Request) {}
|
func (h *Handler) serveDeleteShard(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
// serveShardSpaces returns a list of shard spaces.
|
// serveRetentionPolicys returns a list of retention policys.
|
||||||
func (h *Handler) serveShardSpaces(w http.ResponseWriter, r *http.Request) {}
|
func (h *Handler) serveRetentionPolicys(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
// serveCreateShardSpace creates a new shard space.
|
// serveCreateRetentionPolicy creates a new retention policy.
|
||||||
func (h *Handler) serveCreateShardSpace(w http.ResponseWriter, r *http.Request) {}
|
func (h *Handler) serveCreateRetentionPolicy(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
// serveUpdateShardSpace updates an existing shard space.
|
// serveUpdateRetentionPolicy updates an existing retention policy.
|
||||||
func (h *Handler) serveUpdateShardSpace(w http.ResponseWriter, r *http.Request) {}
|
func (h *Handler) serveUpdateRetentionPolicy(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
// serveDeleteShardSpace removes an existing shard space.
|
// serveDeleteRetentionPolicy removes an existing retention policy.
|
||||||
func (h *Handler) serveDeleteShardSpace(w http.ResponseWriter, r *http.Request) {}
|
func (h *Handler) serveDeleteRetentionPolicy(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
// serveServers returns a list of servers in the cluster.
|
// serveServers returns a list of servers in the cluster.
|
||||||
func (h *Handler) serveServers(w http.ResponseWriter, r *http.Request) {}
|
func (h *Handler) serveServers(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
@ -915,15 +915,15 @@ func (self *HTTPServer) convertShardsToMap(shards []*cluster.ShardData) []interf
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HTTPServer) getShardSpaces(w libhttp.ResponseWriter, r *libhttp.Request) {
|
func (self *HTTPServer) getRetentionPolicys(w libhttp.ResponseWriter, r *libhttp.Request) {
|
||||||
self.tryAsClusterAdmin(w, r, func(u User) (int, interface{}) {
|
self.tryAsClusterAdmin(w, r, func(u User) (int, interface{}) {
|
||||||
return libhttp.StatusOK, self.clusterConfig.GetShardSpaces()
|
return libhttp.StatusOK, self.clusterConfig.GetRetentionPolicys()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HTTPServer) createShardSpace(w libhttp.ResponseWriter, r *libhttp.Request) {
|
func (self *HTTPServer) createRetentionPolicy(w libhttp.ResponseWriter, r *libhttp.Request) {
|
||||||
self.tryAsClusterAdmin(w, r, func(u User) (int, interface{}) {
|
self.tryAsClusterAdmin(w, r, func(u User) (int, interface{}) {
|
||||||
space := &cluster.ShardSpace{}
|
space := &cluster.RetentionPolicy{}
|
||||||
decoder := json.NewDecoder(r.Body)
|
decoder := json.NewDecoder(r.Body)
|
||||||
err := decoder.Decode(space)
|
err := decoder.Decode(space)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -934,7 +934,7 @@ func (self *HTTPServer) createShardSpace(w libhttp.ResponseWriter, r *libhttp.Re
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return libhttp.StatusBadRequest, err.Error()
|
return libhttp.StatusBadRequest, err.Error()
|
||||||
}
|
}
|
||||||
err = self.raftServer.CreateShardSpace(space)
|
err = self.raftServer.CreateRetentionPolicy(space)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return libhttp.StatusInternalServerError, err.Error()
|
return libhttp.StatusInternalServerError, err.Error()
|
||||||
}
|
}
|
||||||
|
@ -942,11 +942,11 @@ func (self *HTTPServer) createShardSpace(w libhttp.ResponseWriter, r *libhttp.Re
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HTTPServer) dropShardSpace(w libhttp.ResponseWriter, r *libhttp.Request) {
|
func (self *HTTPServer) dropRetentionPolicy(w libhttp.ResponseWriter, r *libhttp.Request) {
|
||||||
self.tryAsClusterAdmin(w, r, func(u User) (int, interface{}) {
|
self.tryAsClusterAdmin(w, r, func(u User) (int, interface{}) {
|
||||||
name := r.URL.Query().Get(":name")
|
name := r.URL.Query().Get(":name")
|
||||||
db := r.URL.Query().Get(":db")
|
db := r.URL.Query().Get(":db")
|
||||||
if err := self.raftServer.DropShardSpace(db, name); err != nil {
|
if err := self.raftServer.DropRetentionPolicy(db, name); err != nil {
|
||||||
return libhttp.StatusInternalServerError, err.Error()
|
return libhttp.StatusInternalServerError, err.Error()
|
||||||
}
|
}
|
||||||
return libhttp.StatusOK, nil
|
return libhttp.StatusOK, nil
|
||||||
|
@ -954,7 +954,7 @@ func (self *HTTPServer) dropShardSpace(w libhttp.ResponseWriter, r *libhttp.Requ
|
||||||
}
|
}
|
||||||
|
|
||||||
type DatabaseConfig struct {
|
type DatabaseConfig struct {
|
||||||
Spaces []*cluster.ShardSpace `json:"spaces"`
|
Spaces []*cluster.RetentionPolicy `json:"spaces"`
|
||||||
ContinuousQueries []string `json:"continuousQueries"`
|
ContinuousQueries []string `json:"continuousQueries"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -981,7 +981,7 @@ func (self *HTTPServer) configureDatabase(w libhttp.ResponseWriter, r *libhttp.R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate shard spaces
|
// validate retention policys
|
||||||
for _, space := range databaseConfig.Spaces {
|
for _, space := range databaseConfig.Spaces {
|
||||||
err := space.Validate(self.clusterConfig, false)
|
err := space.Validate(self.clusterConfig, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -995,7 +995,7 @@ func (self *HTTPServer) configureDatabase(w libhttp.ResponseWriter, r *libhttp.R
|
||||||
}
|
}
|
||||||
for _, space := range databaseConfig.Spaces {
|
for _, space := range databaseConfig.Spaces {
|
||||||
space.Database = database
|
space.Database = database
|
||||||
err = self.raftServer.CreateShardSpace(space)
|
err = self.raftServer.CreateRetentionPolicy(space)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return libhttp.StatusInternalServerError, err.Error()
|
return libhttp.StatusInternalServerError, err.Error()
|
||||||
}
|
}
|
||||||
|
@ -1010,9 +1010,9 @@ func (self *HTTPServer) configureDatabase(w libhttp.ResponseWriter, r *libhttp.R
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HTTPServer) updateShardSpace(w libhttp.ResponseWriter, r *libhttp.Request) {
|
func (self *HTTPServer) updateRetentionPolicy(w libhttp.ResponseWriter, r *libhttp.Request) {
|
||||||
self.tryAsClusterAdmin(w, r, func(u User) (int, interface{}) {
|
self.tryAsClusterAdmin(w, r, func(u User) (int, interface{}) {
|
||||||
space := &cluster.ShardSpace{}
|
space := &cluster.RetentionPolicy{}
|
||||||
decoder := json.NewDecoder(r.Body)
|
decoder := json.NewDecoder(r.Body)
|
||||||
err := decoder.Decode(space)
|
err := decoder.Decode(space)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1021,13 +1021,13 @@ func (self *HTTPServer) updateShardSpace(w libhttp.ResponseWriter, r *libhttp.Re
|
||||||
space.Database = r.URL.Query().Get(":db")
|
space.Database = r.URL.Query().Get(":db")
|
||||||
space.Name = r.URL.Query().Get(":name")
|
space.Name = r.URL.Query().Get(":name")
|
||||||
if !self.clusterConfig.DatabaseExists(space.Database) {
|
if !self.clusterConfig.DatabaseExists(space.Database) {
|
||||||
return libhttp.StatusNotAcceptable, "Can't update a shard space for a database that doesn't exist"
|
return libhttp.StatusNotAcceptable, "Can't update a retention policy for a database that doesn't exist"
|
||||||
}
|
}
|
||||||
if !self.clusterConfig.ShardSpaceExists(space) {
|
if !self.clusterConfig.RetentionPolicyExists(space) {
|
||||||
return libhttp.StatusNotAcceptable, "Can't update a shard space that doesn't exist"
|
return libhttp.StatusNotAcceptable, "Can't update a retention policy that doesn't exist"
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := self.raftServer.UpdateShardSpace(space); err != nil {
|
if err := self.raftServer.UpdateRetentionPolicy(space); err != nil {
|
||||||
return libhttp.StatusInternalServerError, err.Error()
|
return libhttp.StatusInternalServerError, err.Error()
|
||||||
}
|
}
|
||||||
return libhttp.StatusOK, nil
|
return libhttp.StatusOK, nil
|
||||||
|
|
12
influxdb.go
12
influxdb.go
|
@ -41,14 +41,14 @@ var (
|
||||||
// ErrInvalidUsername is returned when using a username with invalid characters.
|
// ErrInvalidUsername is returned when using a username with invalid characters.
|
||||||
ErrInvalidUsername = errors.New("invalid username")
|
ErrInvalidUsername = errors.New("invalid username")
|
||||||
|
|
||||||
// ErrShardSpaceExists is returned when creating a duplicate shard space.
|
// ErrRetentionPolicyExists is returned when creating a duplicate shard space.
|
||||||
ErrShardSpaceExists = errors.New("shard space exists")
|
ErrRetentionPolicyExists = errors.New("retention policy exists")
|
||||||
|
|
||||||
// ErrShardSpaceNotFound is returned when deleting a non-existent shard space.
|
// ErrRetentionPolicyNotFound is returned when deleting a non-existent shard space.
|
||||||
ErrShardSpaceNotFound = errors.New("shard space not found")
|
ErrRetentionPolicyNotFound = errors.New("retention policy not found")
|
||||||
|
|
||||||
// ErrShardSpaceNameRequired is returned using a blank shard space name.
|
// ErrRetentionPolicyNameRequired is returned using a blank shard space name.
|
||||||
ErrShardSpaceNameRequired = errors.New("shard space name required")
|
ErrRetentionPolicyNameRequired = errors.New("retention policy name required")
|
||||||
|
|
||||||
// ErrShardNotFound is returned writing to a non-existent shard.
|
// ErrShardNotFound is returned writing to a non-existent shard.
|
||||||
ErrShardNotFound = errors.New("shard not found")
|
ErrShardNotFound = errors.New("shard not found")
|
||||||
|
|
67
server.go
67
server.go
|
@ -19,8 +19,8 @@ const (
|
||||||
// It is also used when reseting the root user's password.
|
// It is also used when reseting the root user's password.
|
||||||
DefaultRootPassword = "root"
|
DefaultRootPassword = "root"
|
||||||
|
|
||||||
// DefaultShardSpaceName is the name of a databases's default shard space.
|
// DefaultRetentionPolicyName is the name of a databases's default shard space.
|
||||||
DefaultShardSpaceName = "default"
|
DefaultRetentionPolicyName = "default"
|
||||||
|
|
||||||
// DefaultSplitN represents the number of partitions a shard is split into.
|
// DefaultSplitN represents the number of partitions a shard is split into.
|
||||||
DefaultSplitN = 1
|
DefaultSplitN = 1
|
||||||
|
@ -39,8 +39,8 @@ const (
|
||||||
// broadcast messages
|
// broadcast messages
|
||||||
createDatabaseMessageType = messaging.MessageType(0x00)
|
createDatabaseMessageType = messaging.MessageType(0x00)
|
||||||
deleteDatabaseMessageType = messaging.MessageType(0x01)
|
deleteDatabaseMessageType = messaging.MessageType(0x01)
|
||||||
createShardSpaceMessageType = messaging.MessageType(0x02)
|
createRetentionPolicyMessageType = messaging.MessageType(0x02)
|
||||||
deleteShardSpaceMessageType = messaging.MessageType(0x03)
|
deleteRetentionPolicyMessageType = messaging.MessageType(0x03)
|
||||||
createClusterAdminMessageType = messaging.MessageType(0x04)
|
createClusterAdminMessageType = messaging.MessageType(0x04)
|
||||||
deleteClusterAdminMessageType = messaging.MessageType(0x05)
|
deleteClusterAdminMessageType = messaging.MessageType(0x05)
|
||||||
clusterAdminSetPasswordMessageType = messaging.MessageType(0x06)
|
clusterAdminSetPasswordMessageType = messaging.MessageType(0x06)
|
||||||
|
@ -48,6 +48,7 @@ const (
|
||||||
deleteDBUserMessageType = messaging.MessageType(0x08)
|
deleteDBUserMessageType = messaging.MessageType(0x08)
|
||||||
dbUserSetPasswordMessageType = messaging.MessageType(0x09)
|
dbUserSetPasswordMessageType = messaging.MessageType(0x09)
|
||||||
createShardIfNotExistsMessageType = messaging.MessageType(0x0a)
|
createShardIfNotExistsMessageType = messaging.MessageType(0x0a)
|
||||||
|
setDefaultRetentionPolicyMessageType = messaging.MessageType(0x0b)
|
||||||
|
|
||||||
// per-topic messages
|
// per-topic messages
|
||||||
writeSeriesMessageType = messaging.MessageType(0x80)
|
writeSeriesMessageType = messaging.MessageType(0x80)
|
||||||
|
@ -541,8 +542,8 @@ type deleteDBUserCommand struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) applyCreateShardSpace(m *messaging.Message) error {
|
func (s *Server) applyCreateRetentionPolicy(m *messaging.Message) error {
|
||||||
var c createShardSpaceCommand
|
var c createRetentionPolicyCommand
|
||||||
mustUnmarshalJSON(m.Data, &c)
|
mustUnmarshalJSON(m.Data, &c)
|
||||||
|
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
|
@ -554,7 +555,7 @@ func (s *Server) applyCreateShardSpace(m *messaging.Message) error {
|
||||||
return ErrDatabaseNotFound
|
return ErrDatabaseNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := db.applyCreateShardSpace(c.Name, c.Regex, c.Retention, c.Duration, c.ReplicaN, c.SplitN); err != nil {
|
if err := db.applyCreateRetentionPolicy(c.Name, c.Duration, c.ReplicaN, c.SplitN); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,18 +567,16 @@ func (s *Server) applyCreateShardSpace(m *messaging.Message) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type createShardSpaceCommand struct {
|
type createRetentionPolicyCommand struct {
|
||||||
Database string `json:"database"`
|
Database string `json:"database"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Regex string `json:"regex"`
|
|
||||||
Retention time.Duration `json:"retention"`
|
|
||||||
Duration time.Duration `json:"duration"`
|
Duration time.Duration `json:"duration"`
|
||||||
ReplicaN uint32 `json:"replicaN"`
|
ReplicaN uint32 `json:"replicaN"`
|
||||||
SplitN uint32 `json:"splitN"`
|
SplitN uint32 `json:"splitN"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) applyDeleteShardSpace(m *messaging.Message) error {
|
func (s *Server) applyDeleteRetentionPolicy(m *messaging.Message) error {
|
||||||
var c deleteShardSpaceCommand
|
var c deleteRetentionPolicyCommand
|
||||||
mustUnmarshalJSON(m.Data, &c)
|
mustUnmarshalJSON(m.Data, &c)
|
||||||
|
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
|
@ -590,7 +589,7 @@ func (s *Server) applyDeleteShardSpace(m *messaging.Message) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove shard space from database.
|
// Remove shard space from database.
|
||||||
if err := db.applyDeleteShardSpace(c.Name); err != nil {
|
if err := db.applyDeleteRetentionPolicy(c.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +601,37 @@ func (s *Server) applyDeleteShardSpace(m *messaging.Message) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type deleteShardSpaceCommand struct {
|
type deleteRetentionPolicyCommand struct {
|
||||||
|
Database string `json:"database"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) applySetDefaultRetentionPolicy(m *messaging.Message) error {
|
||||||
|
var c setDefaultRetentionPolicyCommand
|
||||||
|
mustUnmarshalJSON(m.Data, &c)
|
||||||
|
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
// Retrieve the database.
|
||||||
|
db := s.databases[c.Database]
|
||||||
|
if s.databases[c.Database] == nil {
|
||||||
|
return ErrDatabaseNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.applySetDefaultRetentionPolicy(c.Name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persist to metastore.
|
||||||
|
s.meta.mustUpdate(func(tx *metatx) error {
|
||||||
|
return tx.saveDatabase(db)
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type setDefaultRetentionPolicyCommand struct {
|
||||||
Database string `json:"database"`
|
Database string `json:"database"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
@ -660,12 +689,14 @@ func (s *Server) processor(done chan struct{}) {
|
||||||
err = s.applyDeleteDBUser(m)
|
err = s.applyDeleteDBUser(m)
|
||||||
case dbUserSetPasswordMessageType:
|
case dbUserSetPasswordMessageType:
|
||||||
err = s.applyDBUserSetPassword(m)
|
err = s.applyDBUserSetPassword(m)
|
||||||
case createShardSpaceMessageType:
|
case createRetentionPolicyMessageType:
|
||||||
err = s.applyCreateShardSpace(m)
|
err = s.applyCreateRetentionPolicy(m)
|
||||||
case deleteShardSpaceMessageType:
|
case deleteRetentionPolicyMessageType:
|
||||||
err = s.applyDeleteShardSpace(m)
|
err = s.applyDeleteRetentionPolicy(m)
|
||||||
case createShardIfNotExistsMessageType:
|
case createShardIfNotExistsMessageType:
|
||||||
err = s.applyCreateShardIfNotExists(m)
|
err = s.applyCreateShardIfNotExists(m)
|
||||||
|
case setDefaultRetentionPolicyMessageType:
|
||||||
|
err = s.applySetDefaultRetentionPolicy(m)
|
||||||
case writeSeriesMessageType:
|
case writeSeriesMessageType:
|
||||||
/* TEMPORARILY REMOVED FOR PROTOBUFS.
|
/* TEMPORARILY REMOVED FOR PROTOBUFS.
|
||||||
err = s.applyWriteSeries(m)
|
err = s.applyWriteSeries(m)
|
||||||
|
|
Loading…
Reference in New Issue