Merge branch 'master' of https://github.com/influxdb/influxdb into raft
Conflicts: CHANGELOG.mdpull/2257/head
commit
e3e98d67b1
|
@ -5,6 +5,8 @@
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
- [#2255](https://github.com/influxdb/influxdb/pull/2255): Fix panic when changing default retention policy.
|
- [#2255](https://github.com/influxdb/influxdb/pull/2255): Fix panic when changing default retention policy.
|
||||||
- [#2257](https://github.com/influxdb/influxdb/pull/2257): Add "snapshotting" pseudo state & log entry cache.
|
- [#2257](https://github.com/influxdb/influxdb/pull/2257): Add "snapshotting" pseudo state & log entry cache.
|
||||||
|
- [#2261](https://github.com/influxdb/influxdb/pull/2261): Support int64 value types.
|
||||||
|
- [#2191](https://github.com/influxdb/influxdb/pull/2191): Case-insensitive check for "fill"
|
||||||
|
|
||||||
## v0.9.0-rc23 [2015-04-11]
|
## v0.9.0-rc23 [2015-04-11]
|
||||||
|
|
||||||
|
|
|
@ -84,13 +84,19 @@ func main() {
|
||||||
c.connect("")
|
c.connect("")
|
||||||
|
|
||||||
if c.ShouldDump {
|
if c.ShouldDump {
|
||||||
c.dump()
|
if err := c.dump(); err != nil {
|
||||||
return
|
os.Exit(1)
|
||||||
|
} else {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Execute != "" {
|
if c.Execute != "" {
|
||||||
c.executeQuery(c.Execute)
|
if err := c.executeQuery(c.Execute); err != nil {
|
||||||
return
|
os.Exit(1)
|
||||||
|
} else {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("InfluxDB shell " + version)
|
fmt.Println("InfluxDB shell " + version)
|
||||||
|
@ -264,33 +270,38 @@ func (c *CommandLine) SetFormat(cmd string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommandLine) dump() {
|
func (c *CommandLine) dump() error {
|
||||||
response, err := c.Client.Dump(c.Database)
|
response, err := c.Client.Dump(c.Database)
|
||||||
defer response.Close()
|
defer response.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Dump failed. %s\n", err)
|
fmt.Printf("Dump failed. %s\n", err)
|
||||||
|
return err
|
||||||
} else {
|
} else {
|
||||||
_, err := io.Copy(os.Stdout, response)
|
_, err := io.Copy(os.Stdout, response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Dump failed. %s\n", err)
|
fmt.Printf("Dump failed. %s\n", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommandLine) executeQuery(query string) {
|
func (c *CommandLine) executeQuery(query string) error {
|
||||||
response, err := c.Client.Query(client.Query{Command: query, Database: c.Database})
|
response, err := c.Client.Query(client.Query{Command: query, Database: c.Database})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("ERR: %s\n", err)
|
fmt.Printf("ERR: %s\n", err)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
c.FormatResponse(response, os.Stdout)
|
c.FormatResponse(response, os.Stdout)
|
||||||
if response.Error() != nil {
|
if err := response.Error(); err != nil {
|
||||||
fmt.Printf("ERR: %s\n", response.Error())
|
fmt.Printf("ERR: %s\n", response.Error())
|
||||||
if c.Database == "" {
|
if c.Database == "" {
|
||||||
fmt.Println("Warning: It is possible this error is due to not setting a database.")
|
fmt.Println("Warning: It is possible this error is due to not setting a database.")
|
||||||
fmt.Println(`Please set a database with the command "use <database>".`)
|
fmt.Println(`Please set a database with the command "use <database>".`)
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommandLine) FormatResponse(response *client.Response, w io.Writer) {
|
func (c *CommandLine) FormatResponse(response *client.Response, w io.Writer) {
|
||||||
|
|
26
database.go
26
database.go
|
@ -780,17 +780,14 @@ func (f *FieldCodec) EncodeFields(values map[string]interface{}) ([]byte, error)
|
||||||
var buf []byte
|
var buf []byte
|
||||||
|
|
||||||
switch field.Type {
|
switch field.Type {
|
||||||
case influxql.Number:
|
case influxql.Float:
|
||||||
var value float64
|
value := v.(float64)
|
||||||
// Convert integers to floats.
|
|
||||||
if intval, ok := v.(int); ok {
|
|
||||||
value = float64(intval)
|
|
||||||
} else {
|
|
||||||
value = v.(float64)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = make([]byte, 9)
|
buf = make([]byte, 9)
|
||||||
binary.BigEndian.PutUint64(buf[1:9], math.Float64bits(value))
|
binary.BigEndian.PutUint64(buf[1:9], math.Float64bits(value))
|
||||||
|
case influxql.Integer:
|
||||||
|
value := v.(int64)
|
||||||
|
buf = make([]byte, 9)
|
||||||
|
binary.BigEndian.PutUint64(buf[1:9], uint64(value))
|
||||||
case influxql.Boolean:
|
case influxql.Boolean:
|
||||||
value := v.(bool)
|
value := v.(bool)
|
||||||
|
|
||||||
|
@ -850,10 +847,13 @@ func (f *FieldCodec) DecodeByID(targetID uint8, b []byte) (interface{}, error) {
|
||||||
|
|
||||||
var value interface{}
|
var value interface{}
|
||||||
switch field.Type {
|
switch field.Type {
|
||||||
case influxql.Number:
|
case influxql.Float:
|
||||||
// Move bytes forward.
|
// Move bytes forward.
|
||||||
value = math.Float64frombits(binary.BigEndian.Uint64(b[1:9]))
|
value = math.Float64frombits(binary.BigEndian.Uint64(b[1:9]))
|
||||||
b = b[9:]
|
b = b[9:]
|
||||||
|
case influxql.Integer:
|
||||||
|
value = int64(binary.BigEndian.Uint64(b[1:9]))
|
||||||
|
b = b[9:]
|
||||||
case influxql.Boolean:
|
case influxql.Boolean:
|
||||||
if b[1] == 1 {
|
if b[1] == 1 {
|
||||||
value = true
|
value = true
|
||||||
|
@ -904,10 +904,14 @@ func (f *FieldCodec) DecodeFields(b []byte) (map[uint8]interface{}, error) {
|
||||||
|
|
||||||
var value interface{}
|
var value interface{}
|
||||||
switch field.Type {
|
switch field.Type {
|
||||||
case influxql.Number:
|
case influxql.Float:
|
||||||
value = math.Float64frombits(binary.BigEndian.Uint64(b[1:9]))
|
value = math.Float64frombits(binary.BigEndian.Uint64(b[1:9]))
|
||||||
// Move bytes forward.
|
// Move bytes forward.
|
||||||
b = b[9:]
|
b = b[9:]
|
||||||
|
case influxql.Integer:
|
||||||
|
value = int64(binary.BigEndian.Uint64(b[1:9]))
|
||||||
|
// Move bytes forward.
|
||||||
|
b = b[9:]
|
||||||
case influxql.Boolean:
|
case influxql.Boolean:
|
||||||
if b[1] == 1 {
|
if b[1] == 1 {
|
||||||
value = true
|
value = true
|
||||||
|
|
|
@ -1564,7 +1564,7 @@ func TestHandler_serveWriteSeriesFieldTypeConflict(t *testing.T) {
|
||||||
if len(r.Results) != 0 {
|
if len(r.Results) != 0 {
|
||||||
t.Fatalf("unexpected results count")
|
t.Fatalf("unexpected results count")
|
||||||
}
|
}
|
||||||
if r.Err.Error() != "field \"value\" is type string, mapped as type number" {
|
if r.Err.Error() != "field \"value\" is type string, mapped as type float" {
|
||||||
t.Fatalf("unexpected error returned, actual: %s", r.Err.Error())
|
t.Fatalf("unexpected error returned, actual: %s", r.Err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,10 @@ type DataType string
|
||||||
const (
|
const (
|
||||||
// Unknown primitive data type.
|
// Unknown primitive data type.
|
||||||
Unknown = DataType("")
|
Unknown = DataType("")
|
||||||
// Number means the data type is an int or float.
|
// Float means the data type is a float
|
||||||
Number = DataType("number")
|
Float = DataType("float")
|
||||||
|
// Integer means the data type is a integer
|
||||||
|
Integer = DataType("integer")
|
||||||
// Boolean means the data type is a boolean.
|
// Boolean means the data type is a boolean.
|
||||||
Boolean = DataType("boolean")
|
Boolean = DataType("boolean")
|
||||||
// String means the data type is a string of text.
|
// String means the data type is a string of text.
|
||||||
|
@ -33,9 +35,9 @@ const (
|
||||||
func InspectDataType(v interface{}) DataType {
|
func InspectDataType(v interface{}) DataType {
|
||||||
switch v.(type) {
|
switch v.(type) {
|
||||||
case float64:
|
case float64:
|
||||||
return Number
|
return Float
|
||||||
case int:
|
case int64, int32, int:
|
||||||
return Number
|
return Integer
|
||||||
case bool:
|
case bool:
|
||||||
return Boolean
|
return Boolean
|
||||||
case string:
|
case string:
|
||||||
|
|
|
@ -16,7 +16,7 @@ func TestInspectDataType(t *testing.T) {
|
||||||
v interface{}
|
v interface{}
|
||||||
typ influxql.DataType
|
typ influxql.DataType
|
||||||
}{
|
}{
|
||||||
{float64(100), influxql.Number},
|
{float64(100), influxql.Float},
|
||||||
} {
|
} {
|
||||||
if typ := influxql.InspectDataType(tt.v); tt.typ != typ {
|
if typ := influxql.InspectDataType(tt.v); tt.typ != typ {
|
||||||
t.Errorf("%d. %v (%s): unexpected type: %s", i, tt.v, tt.typ, typ)
|
t.Errorf("%d. %v (%s): unexpected type: %s", i, tt.v, tt.typ, typ)
|
||||||
|
|
|
@ -1558,7 +1558,7 @@ func (p *Parser) parseFill() (FillOption, interface{}, error) {
|
||||||
p.unscan()
|
p.unscan()
|
||||||
return NullFill, nil, nil
|
return NullFill, nil, nil
|
||||||
} else {
|
} else {
|
||||||
if lit.Name != "fill" {
|
if strings.ToLower(lit.Name) != "fill" {
|
||||||
p.unscan()
|
p.unscan()
|
||||||
return NullFill, nil, nil
|
return NullFill, nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -317,6 +317,20 @@ func TestParser_ParseStatement(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// SELECT statement with FILL(none) -- check case insensitivity
|
||||||
|
{
|
||||||
|
s: `SELECT mean(value) FROM cpu GROUP BY time(5m) FILL(none)`,
|
||||||
|
stmt: &influxql.SelectStatement{
|
||||||
|
Fields: []*influxql.Field{{
|
||||||
|
Expr: &influxql.Call{
|
||||||
|
Name: "mean",
|
||||||
|
Args: []influxql.Expr{&influxql.VarRef{Val: "value"}}}}},
|
||||||
|
Sources: []influxql.Source{&influxql.Measurement{Name: "cpu"}},
|
||||||
|
Dimensions: []*influxql.Dimension{{Expr: &influxql.Call{Name: "time", Args: []influxql.Expr{&influxql.DurationLiteral{Val: 5 * time.Minute}}}}},
|
||||||
|
Fill: influxql.NoFill,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
// SELECT statement with previous fill
|
// SELECT statement with previous fill
|
||||||
{
|
{
|
||||||
s: `SELECT mean(value) FROM cpu GROUP BY time(5m) fill(previous)`,
|
s: `SELECT mean(value) FROM cpu GROUP BY time(5m) fill(previous)`,
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
func TestMeasurement_uniqueTagValues(t *testing.T) {
|
func TestMeasurement_uniqueTagValues(t *testing.T) {
|
||||||
// Create a measurement to run against.
|
// Create a measurement to run against.
|
||||||
m := NewMeasurement("cpu")
|
m := NewMeasurement("cpu")
|
||||||
m.createFieldIfNotExists("value", influxql.Number)
|
m.createFieldIfNotExists("value", influxql.Float)
|
||||||
|
|
||||||
for i, tt := range []struct {
|
for i, tt := range []struct {
|
||||||
expr string
|
expr string
|
||||||
|
@ -37,7 +37,7 @@ func TestMeasurement_uniqueTagValues(t *testing.T) {
|
||||||
// Ensure a measurement can expand an expression for all possible tag values used.
|
// Ensure a measurement can expand an expression for all possible tag values used.
|
||||||
func TestMeasurement_expandExpr(t *testing.T) {
|
func TestMeasurement_expandExpr(t *testing.T) {
|
||||||
m := NewMeasurement("cpu")
|
m := NewMeasurement("cpu")
|
||||||
m.createFieldIfNotExists("value", influxql.Number)
|
m.createFieldIfNotExists("value", influxql.Float)
|
||||||
|
|
||||||
type tagSetExprString struct {
|
type tagSetExprString struct {
|
||||||
tagExpr []tagExpr
|
tagExpr []tagExpr
|
||||||
|
@ -129,13 +129,13 @@ func TestCreateMeasurementsCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a field.
|
// Add a field.
|
||||||
err = c.addFieldIfNotExists("bar", "value", influxql.Number)
|
err = c.addFieldIfNotExists("bar", "value", influxql.Integer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error adding field \"value\"")
|
t.Fatal("error adding field \"value\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add same field again.
|
// Add same field again.
|
||||||
err = c.addFieldIfNotExists("bar", "value", influxql.Number)
|
err = c.addFieldIfNotExists("bar", "value", influxql.Integer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error re-adding field \"value\"")
|
t.Fatal("error re-adding field \"value\"")
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,7 @@ func TestCreateMeasurementsCommand_Errors(t *testing.T) {
|
||||||
// Measurements should be created automatically.
|
// Measurements should be created automatically.
|
||||||
c.addSeriesIfNotExists("bar", nil)
|
c.addSeriesIfNotExists("bar", nil)
|
||||||
|
|
||||||
err = c.addFieldIfNotExists("bar", "value", influxql.Number)
|
err = c.addFieldIfNotExists("bar", "value", influxql.Float)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error got %s", err.Error())
|
t.Fatalf("unexpected error got %s", err.Error())
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ func TestCreateMeasurementsCommand_Errors(t *testing.T) {
|
||||||
c.addMeasurementIfNotExists("bar")
|
c.addMeasurementIfNotExists("bar")
|
||||||
|
|
||||||
// Test type conflicts
|
// Test type conflicts
|
||||||
err = c.addFieldIfNotExists("bar", "value", influxql.Number)
|
err = c.addFieldIfNotExists("bar", "value", influxql.Float)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error adding field \"value\"")
|
t.Fatal("error adding field \"value\"")
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -44,6 +45,10 @@ func TestLog_Open_ErrMkdir(t *testing.T) {
|
||||||
|
|
||||||
// Ensure that opening a log with an inaccessible ID path returns an error.
|
// Ensure that opening a log with an inaccessible ID path returns an error.
|
||||||
func TestLog_Open_ErrInaccessibleID(t *testing.T) {
|
func TestLog_Open_ErrInaccessibleID(t *testing.T) {
|
||||||
|
if "windows" == runtime.GOOS {
|
||||||
|
t.Skip("skip it on the windows")
|
||||||
|
}
|
||||||
|
|
||||||
path := tempfile()
|
path := tempfile()
|
||||||
MustWriteFile(filepath.Join(path, "id"), []byte(`1`))
|
MustWriteFile(filepath.Join(path, "id"), []byte(`1`))
|
||||||
MustChmod(filepath.Join(path, "id"), 0)
|
MustChmod(filepath.Join(path, "id"), 0)
|
||||||
|
@ -73,6 +78,10 @@ func TestLog_Open_ErrInvalidID(t *testing.T) {
|
||||||
|
|
||||||
// Ensure that opening a log with an inaccesible term path returns an error.
|
// Ensure that opening a log with an inaccesible term path returns an error.
|
||||||
func TestLog_Open_ErrInaccessibleTerm(t *testing.T) {
|
func TestLog_Open_ErrInaccessibleTerm(t *testing.T) {
|
||||||
|
if "windows" == runtime.GOOS {
|
||||||
|
t.Skip("skip it on the windows")
|
||||||
|
}
|
||||||
|
|
||||||
path := tempfile()
|
path := tempfile()
|
||||||
MustWriteFile(filepath.Join(path, "id"), []byte(`1`))
|
MustWriteFile(filepath.Join(path, "id"), []byte(`1`))
|
||||||
MustWriteFile(filepath.Join(path, "term"), []byte(`1`))
|
MustWriteFile(filepath.Join(path, "term"), []byte(`1`))
|
||||||
|
@ -104,6 +113,10 @@ func TestLog_Open_ErrInvalidTerm(t *testing.T) {
|
||||||
|
|
||||||
// Ensure that opening an inaccessible config path returns an error.
|
// Ensure that opening an inaccessible config path returns an error.
|
||||||
func TestLog_Open_ErrInaccessibleConfig(t *testing.T) {
|
func TestLog_Open_ErrInaccessibleConfig(t *testing.T) {
|
||||||
|
if "windows" == runtime.GOOS {
|
||||||
|
t.Skip("skip it on the windows")
|
||||||
|
}
|
||||||
|
|
||||||
path := tempfile()
|
path := tempfile()
|
||||||
MustWriteFile(filepath.Join(path, "id"), []byte(`1`))
|
MustWriteFile(filepath.Join(path, "id"), []byte(`1`))
|
||||||
MustWriteFile(filepath.Join(path, "term"), []byte(`1`))
|
MustWriteFile(filepath.Join(path, "term"), []byte(`1`))
|
||||||
|
|
|
@ -976,6 +976,40 @@ func TestServer_StartRetentionPolicyEnforcement_ErrZeroInterval(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure the server can support writes of all data types.
|
||||||
|
func TestServer_WriteAllDataTypes(t *testing.T) {
|
||||||
|
c := test.NewDefaultMessagingClient()
|
||||||
|
defer c.Close()
|
||||||
|
s := OpenServer(c)
|
||||||
|
defer s.Close()
|
||||||
|
s.CreateDatabase("foo")
|
||||||
|
s.CreateRetentionPolicy("foo", &influxdb.RetentionPolicy{Name: "raw", Duration: 1 * time.Hour})
|
||||||
|
s.SetDefaultRetentionPolicy("foo", "raw")
|
||||||
|
|
||||||
|
// Write series with one point to the database.
|
||||||
|
s.MustWriteSeries("foo", "raw", []influxdb.Point{{Name: "series1", Timestamp: mustParseTime("2000-01-01T00:00:00Z"), Fields: map[string]interface{}{"value": float64(20)}}})
|
||||||
|
s.MustWriteSeries("foo", "raw", []influxdb.Point{{Name: "series2", Timestamp: mustParseTime("2000-01-01T00:00:00Z"), Fields: map[string]interface{}{"value": int64(30)}}})
|
||||||
|
s.MustWriteSeries("foo", "raw", []influxdb.Point{{Name: "series3", Timestamp: mustParseTime("2000-01-01T00:00:00Z"), Fields: map[string]interface{}{"value": "baz"}}})
|
||||||
|
s.MustWriteSeries("foo", "raw", []influxdb.Point{{Name: "series4", Timestamp: mustParseTime("2000-01-01T00:00:00Z"), Fields: map[string]interface{}{"value": true}}})
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
|
||||||
|
f := func(t *testing.T, database, query, expected string) {
|
||||||
|
results := s.executeQuery(MustParseQuery(query), database, nil)
|
||||||
|
if res := results.Results[0]; res.Err != nil {
|
||||||
|
t.Errorf("unexpected error: %s", res.Err)
|
||||||
|
} else if len(res.Series) != 1 {
|
||||||
|
t.Errorf("unexpected row count: %d", len(res.Series))
|
||||||
|
} else if s := mustMarshalJSON(res); s != expected {
|
||||||
|
t.Errorf("unexpected row(0): \nexp: %s\ngot: %s", expected, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f(t, "foo", "SELECT * from series1", `{"series":[{"name":"series1","columns":["time","value"],"values":[["2000-01-01T00:00:00Z",20]]}]}`)
|
||||||
|
f(t, "foo", "SELECT * from series2", `{"series":[{"name":"series2","columns":["time","value"],"values":[["2000-01-01T00:00:00Z",30]]}]}`)
|
||||||
|
f(t, "foo", "SELECT * from series3", `{"series":[{"name":"series3","columns":["time","value"],"values":[["2000-01-01T00:00:00Z","baz"]]}]}`)
|
||||||
|
f(t, "foo", "SELECT * from series4", `{"series":[{"name":"series4","columns":["time","value"],"values":[["2000-01-01T00:00:00Z",true]]}]}`)
|
||||||
|
}
|
||||||
|
|
||||||
func TestServer_EnforceRetentionPolices(t *testing.T) {
|
func TestServer_EnforceRetentionPolices(t *testing.T) {
|
||||||
c := test.NewDefaultMessagingClient()
|
c := test.NewDefaultMessagingClient()
|
||||||
s := OpenServer(c)
|
s := OpenServer(c)
|
||||||
|
|
Loading…
Reference in New Issue