2015-07-16 00:52:24 +00:00
|
|
|
package cluster
|
|
|
|
|
|
|
|
import (
|
2015-09-16 20:17:58 +00:00
|
|
|
"encoding/json"
|
2015-07-16 21:27:29 +00:00
|
|
|
"fmt"
|
|
|
|
"math/rand"
|
|
|
|
"net"
|
|
|
|
"time"
|
2015-07-16 03:06:07 +00:00
|
|
|
|
2015-08-24 02:55:48 +00:00
|
|
|
"github.com/influxdb/influxdb/influxql"
|
2015-07-16 02:53:10 +00:00
|
|
|
"github.com/influxdb/influxdb/meta"
|
2015-07-16 00:52:24 +00:00
|
|
|
"github.com/influxdb/influxdb/tsdb"
|
2015-07-16 03:06:07 +00:00
|
|
|
)
|
|
|
|
|
2015-07-16 00:52:24 +00:00
|
|
|
// ShardMapper is responsible for providing mappers for requested shards. It is
|
|
|
|
// responsible for creating those mappers from the local store, or reaching
|
|
|
|
// out to another node on the cluster.
|
|
|
|
type ShardMapper struct {
|
2015-07-18 02:02:15 +00:00
|
|
|
ForceRemoteMapping bool // All shards treated as remote. Useful for testing.
|
|
|
|
|
2015-07-16 00:52:24 +00:00
|
|
|
MetaStore interface {
|
|
|
|
NodeID() uint64
|
2015-07-16 21:00:10 +00:00
|
|
|
Node(id uint64) (ni *meta.NodeInfo, err error)
|
2015-07-16 00:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TSDBStore interface {
|
2015-08-24 02:55:48 +00:00
|
|
|
CreateMapper(shardID uint64, stmt influxql.Statement, chunkSize int) (tsdb.Mapper, error)
|
2015-07-16 00:52:24 +00:00
|
|
|
}
|
2015-07-16 21:27:29 +00:00
|
|
|
|
|
|
|
timeout time.Duration
|
|
|
|
pool *clientPool
|
2015-07-16 00:52:24 +00:00
|
|
|
}
|
|
|
|
|
2015-07-16 03:06:07 +00:00
|
|
|
// NewShardMapper returns a mapper of local and remote shards.
|
2015-07-16 21:27:29 +00:00
|
|
|
func NewShardMapper(timeout time.Duration) *ShardMapper {
|
|
|
|
return &ShardMapper{
|
|
|
|
pool: newClientPool(),
|
|
|
|
timeout: timeout,
|
|
|
|
}
|
2015-07-16 00:52:24 +00:00
|
|
|
}
|
|
|
|
|
2015-07-16 03:06:07 +00:00
|
|
|
// CreateMapper returns a Mapper for the given shard ID.
|
2015-08-24 02:55:48 +00:00
|
|
|
func (s *ShardMapper) CreateMapper(sh meta.ShardInfo, stmt influxql.Statement, chunkSize int) (tsdb.Mapper, error) {
|
2015-09-16 20:17:58 +00:00
|
|
|
// Create a remote mapper if the local node doesn't own the shard.
|
2015-08-19 17:12:56 +00:00
|
|
|
if !sh.OwnedBy(s.MetaStore.NodeID()) || s.ForceRemoteMapping {
|
2015-07-16 21:27:29 +00:00
|
|
|
// Pick a node in a pseudo-random manner.
|
2015-08-31 22:03:44 +00:00
|
|
|
conn, err := s.dial(sh.Owners[rand.Intn(len(sh.Owners))].NodeID)
|
2015-07-16 21:27:29 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
conn.SetDeadline(time.Now().Add(s.timeout))
|
|
|
|
|
2015-09-16 20:17:58 +00:00
|
|
|
return NewRemoteMapper(conn, sh.ID, stmt, chunkSize), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// If it is local then return the mapper from the store.
|
|
|
|
m, err := s.TSDBStore.CreateMapper(sh.ID, stmt, chunkSize)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2015-07-16 00:52:24 +00:00
|
|
|
}
|
2015-07-16 02:53:10 +00:00
|
|
|
|
2015-07-16 00:52:24 +00:00
|
|
|
return m, nil
|
|
|
|
}
|
2015-07-16 03:06:07 +00:00
|
|
|
|
2015-07-16 21:27:29 +00:00
|
|
|
func (s *ShardMapper) dial(nodeID uint64) (net.Conn, error) {
|
2015-08-31 20:31:00 +00:00
|
|
|
ni, err := s.MetaStore.Node(nodeID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2015-07-16 21:27:29 +00:00
|
|
|
}
|
2015-08-31 20:31:00 +00:00
|
|
|
conn, err := net.Dial("tcp", ni.Host)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the cluster multiplexing header byte
|
|
|
|
conn.Write([]byte{MuxHeader})
|
2015-07-16 21:27:29 +00:00
|
|
|
|
2015-08-31 20:31:00 +00:00
|
|
|
return conn, nil
|
2015-07-16 21:27:29 +00:00
|
|
|
}
|
|
|
|
|
2015-07-16 03:06:07 +00:00
|
|
|
// RemoteMapper implements the tsdb.Mapper interface. It connects to a remote node,
|
|
|
|
// sends a query, and interprets the stream of data that comes back.
|
|
|
|
type RemoteMapper struct {
|
|
|
|
shardID uint64
|
2015-08-24 02:55:48 +00:00
|
|
|
stmt influxql.Statement
|
2015-07-16 03:06:07 +00:00
|
|
|
chunkSize int
|
|
|
|
|
|
|
|
tagsets []string
|
2015-07-28 22:49:18 +00:00
|
|
|
fields []string
|
2015-07-16 03:06:07 +00:00
|
|
|
|
2015-08-31 20:31:00 +00:00
|
|
|
conn net.Conn
|
2015-07-16 21:27:29 +00:00
|
|
|
bufferedResponse *MapShardResponse
|
2015-09-16 20:17:58 +00:00
|
|
|
|
|
|
|
unmarshallers []tsdb.UnmarshalFunc // Mapping-specific unmarshal functions.
|
2015-07-16 03:06:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-16 21:27:29 +00:00
|
|
|
// NewRemoteMapper returns a new remote mapper using the given connection.
|
2015-08-31 20:31:00 +00:00
|
|
|
func NewRemoteMapper(c net.Conn, shardID uint64, stmt influxql.Statement, chunkSize int) *RemoteMapper {
|
2015-07-16 03:06:07 +00:00
|
|
|
return &RemoteMapper{
|
2015-07-16 21:27:29 +00:00
|
|
|
conn: c,
|
2015-07-16 03:06:07 +00:00
|
|
|
shardID: shardID,
|
|
|
|
stmt: stmt,
|
|
|
|
chunkSize: chunkSize,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open connects to the remote node and starts receiving data.
|
2015-07-16 21:27:29 +00:00
|
|
|
func (r *RemoteMapper) Open() (err error) {
|
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
r.conn.Close()
|
|
|
|
}
|
|
|
|
}()
|
2015-09-16 20:17:58 +00:00
|
|
|
|
2015-07-16 21:27:29 +00:00
|
|
|
// Build Map request.
|
|
|
|
var request MapShardRequest
|
|
|
|
request.SetShardID(r.shardID)
|
2015-08-24 02:55:48 +00:00
|
|
|
request.SetQuery(r.stmt.String())
|
2015-07-16 21:27:29 +00:00
|
|
|
request.SetChunkSize(int32(r.chunkSize))
|
|
|
|
|
|
|
|
// Marshal into protocol buffers.
|
|
|
|
buf, err := request.MarshalBinary()
|
2015-07-16 03:06:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-07-16 21:27:29 +00:00
|
|
|
// Write request.
|
|
|
|
if err := WriteTLV(r.conn, mapShardRequestMessage, buf); err != nil {
|
|
|
|
return err
|
2015-07-16 03:06:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-16 21:27:29 +00:00
|
|
|
// Read the response.
|
|
|
|
_, buf, err = ReadTLV(r.conn)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2015-07-16 03:06:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-16 21:27:29 +00:00
|
|
|
// Unmarshal response.
|
|
|
|
r.bufferedResponse = &MapShardResponse{}
|
|
|
|
if err := r.bufferedResponse.UnmarshalBinary(buf); err != nil {
|
2015-07-16 03:06:07 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-07-16 21:27:29 +00:00
|
|
|
if r.bufferedResponse.Code() != 0 {
|
|
|
|
return fmt.Errorf("error code %d: %s", r.bufferedResponse.Code(), r.bufferedResponse.Message())
|
|
|
|
}
|
2015-07-16 03:06:07 +00:00
|
|
|
|
|
|
|
// Decode the first response to get the TagSets.
|
2015-07-16 21:27:29 +00:00
|
|
|
r.tagsets = r.bufferedResponse.TagSets()
|
2015-08-19 17:12:56 +00:00
|
|
|
r.fields = r.bufferedResponse.Fields()
|
2015-07-16 03:06:07 +00:00
|
|
|
|
2015-09-16 20:17:58 +00:00
|
|
|
// Set up each mapping function for this statement.
|
|
|
|
if stmt, ok := r.stmt.(*influxql.SelectStatement); ok {
|
|
|
|
for _, c := range stmt.FunctionCalls() {
|
|
|
|
fn, err := tsdb.InitializeUnmarshaller(c)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
r.unmarshallers = append(r.unmarshallers, fn)
|
|
|
|
}
|
|
|
|
}
|
2015-07-16 03:06:07 +00:00
|
|
|
|
2015-09-16 20:17:58 +00:00
|
|
|
return nil
|
2015-08-19 17:12:56 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 02:40:58 +00:00
|
|
|
// TagSets returns the TagSets
|
2015-07-16 03:06:07 +00:00
|
|
|
func (r *RemoteMapper) TagSets() []string {
|
|
|
|
return r.tagsets
|
|
|
|
}
|
|
|
|
|
2015-09-29 02:40:58 +00:00
|
|
|
// Fields returns RemoteMapper's Fields
|
2015-07-28 22:49:18 +00:00
|
|
|
func (r *RemoteMapper) Fields() []string {
|
|
|
|
return r.fields
|
|
|
|
}
|
|
|
|
|
2015-07-16 03:06:07 +00:00
|
|
|
// NextChunk returns the next chunk read from the remote node to the client.
|
2015-07-16 21:27:29 +00:00
|
|
|
func (r *RemoteMapper) NextChunk() (chunk interface{}, err error) {
|
|
|
|
var response *MapShardResponse
|
|
|
|
if r.bufferedResponse != nil {
|
|
|
|
response = r.bufferedResponse
|
|
|
|
r.bufferedResponse = nil
|
|
|
|
} else {
|
|
|
|
response = &MapShardResponse{}
|
|
|
|
|
|
|
|
// Read the response.
|
|
|
|
_, buf, err := ReadTLV(r.conn)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unmarshal response.
|
|
|
|
if err := response.UnmarshalBinary(buf); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if response.Code() != 0 {
|
|
|
|
return nil, fmt.Errorf("error code %d: %s", response.Code(), response.Message())
|
|
|
|
}
|
2015-07-16 03:06:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-16 21:27:29 +00:00
|
|
|
if response.Data() == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
2015-08-19 17:12:56 +00:00
|
|
|
|
2015-09-16 20:17:58 +00:00
|
|
|
moj := &tsdb.MapperOutputJSON{}
|
|
|
|
if err := json.Unmarshal(response.Data(), moj); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
mvj := []*tsdb.MapperValueJSON{}
|
|
|
|
if err := json.Unmarshal(moj.Values, &mvj); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prep the non-JSON version of Mapper output.
|
|
|
|
mo := &tsdb.MapperOutput{
|
2015-12-07 22:55:37 +00:00
|
|
|
Name: moj.Name,
|
|
|
|
Tags: moj.Tags,
|
|
|
|
Fields: moj.Fields,
|
|
|
|
CursorKey: moj.CursorKey,
|
2015-09-16 20:17:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(mvj) == 1 && len(mvj[0].AggData) > 0 {
|
|
|
|
// The MapperValue is carrying aggregate data, so run it through the
|
|
|
|
// custom unmarshallers for the map functions through which the data
|
|
|
|
// was mapped.
|
|
|
|
aggValues := []interface{}{}
|
|
|
|
for i, b := range mvj[0].AggData {
|
|
|
|
v, err := r.unmarshallers[i](b)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
aggValues = append(aggValues, v)
|
|
|
|
}
|
|
|
|
mo.Values = []*tsdb.MapperValue{&tsdb.MapperValue{
|
2015-11-17 16:56:05 +00:00
|
|
|
Time: mvj[0].Time,
|
2015-09-16 20:17:58 +00:00
|
|
|
Value: aggValues,
|
|
|
|
Tags: mvj[0].Tags,
|
|
|
|
}}
|
|
|
|
} else {
|
|
|
|
// Must be raw data instead.
|
|
|
|
for _, v := range mvj {
|
|
|
|
var rawValue interface{}
|
|
|
|
if err := json.Unmarshal(v.RawData, &rawValue); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
mo.Values = append(mo.Values, &tsdb.MapperValue{
|
|
|
|
Time: v.Time,
|
|
|
|
Value: rawValue,
|
|
|
|
Tags: v.Tags,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return mo, nil
|
2015-07-16 03:06:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-16 21:27:29 +00:00
|
|
|
// Close the Mapper
|
2015-07-16 03:06:07 +00:00
|
|
|
func (r *RemoteMapper) Close() {
|
2015-07-16 21:27:29 +00:00
|
|
|
r.conn.Close()
|
2015-07-16 03:06:07 +00:00
|
|
|
}
|