Merge pull request #892 from yuce/client-refactoring

Internal Client refactoring
This commit is contained in:
Yuce Tekol 2017-10-24 02:46:02 +03:00 committed by GitHub
commit 569cd90f59
18 changed files with 1156 additions and 587 deletions

217
client.go
View file

@ -32,26 +32,27 @@ import (
"time"
"crypto/tls"
"github.com/gogo/protobuf/proto"
"github.com/pilosa/pilosa/internal"
)
// ClientOptions represents the configuration for a Client
// ClientOptions represents the configuration for a InternalHTTPClient
type ClientOptions struct {
TLS *tls.Config
}
// Client represents a client to the Pilosa cluster.
type Client struct {
host *URI
options *ClientOptions
// InternalHTTPClient represents a client to the Pilosa cluster.
type InternalHTTPClient struct {
defaultURI *URI
options *ClientOptions
// The client to use for HTTP communication.
HTTPClient *http.Client
}
// NewClient returns a new instance of Client to connect to host.
func NewClient(host string, options *ClientOptions) (*Client, error) {
// NewInternalHTTPClient returns a new instance of InternalHTTPClient to connect to host.
func NewInternalHTTPClient(host string, options *ClientOptions) (*InternalHTTPClient, error) {
if host == "" {
return nil, ErrHostRequired
}
@ -61,13 +62,11 @@ func NewClient(host string, options *ClientOptions) (*Client, error) {
return nil, err
}
return NewClientFromURI(uri, options)
client := NewInternalHTTPClientFromURI(uri, options)
return client, nil
}
func NewClientFromURI(uri *URI, options *ClientOptions) (*Client, error) {
if uri == nil {
return nil, ErrHostRequired
}
func NewInternalHTTPClientFromURI(defaultURI *URI, options *ClientOptions) *InternalHTTPClient {
if options == nil {
options = &ClientOptions{}
}
@ -76,29 +75,29 @@ func NewClientFromURI(uri *URI, options *ClientOptions) (*Client, error) {
transport.TLSClientConfig = options.TLS
}
client := &http.Client{Transport: transport}
return &Client{
host: uri,
return &InternalHTTPClient{
defaultURI: defaultURI,
HTTPClient: client,
}, nil
}
}
// Host returns the host the client was initialized with.
func (c *Client) Host() *URI { return c.host }
func (c *InternalHTTPClient) Host() *URI { return c.defaultURI }
// MaxSliceByIndex returns the number of slices on a server by index.
func (c *Client) MaxSliceByIndex(ctx context.Context) (map[string]uint64, error) {
func (c *InternalHTTPClient) MaxSliceByIndex(ctx context.Context) (map[string]uint64, error) {
return c.maxSliceByIndex(ctx, false)
}
// MaxInverseSliceByIndex returns the number of inverse slices on a server by index.
func (c *Client) MaxInverseSliceByIndex(ctx context.Context) (map[string]uint64, error) {
func (c *InternalHTTPClient) MaxInverseSliceByIndex(ctx context.Context) (map[string]uint64, error) {
return c.maxSliceByIndex(ctx, true)
}
// maxSliceByIndex returns the number of slices on a server by index.
func (c *Client) maxSliceByIndex(ctx context.Context, inverse bool) (map[string]uint64, error) {
func (c *InternalHTTPClient) maxSliceByIndex(ctx context.Context, inverse bool) (map[string]uint64, error) {
// Execute request against the host.
u := uriPathToURL(c.host, "/slices/max")
u := uriPathToURL(c.clientURI(ctx), "/slices/max")
u.RawQuery = (&url.Values{
"inverse": {strconv.FormatBool(inverse)},
}).Encode()
@ -129,12 +128,12 @@ func (c *Client) maxSliceByIndex(ctx context.Context, inverse bool) (map[string]
}
// Schema returns all index and frame schema information.
func (c *Client) Schema(ctx context.Context) ([]*IndexInfo, error) {
func (c *InternalHTTPClient) Schema(ctx context.Context) ([]*IndexInfo, error) {
// Execute request against the host.
u := uriPathToURL(c.host, "/schema")
u := c.defaultURI.Path("/schema")
// Build request.
req, err := http.NewRequest("GET", u.String(), nil)
req, err := http.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}
@ -158,7 +157,7 @@ func (c *Client) Schema(ctx context.Context) ([]*IndexInfo, error) {
}
// CreateIndex creates a new index on the server.
func (c *Client) CreateIndex(ctx context.Context, index string, opt IndexOptions) error {
func (c *InternalHTTPClient) CreateIndex(ctx context.Context, index string, opt IndexOptions) error {
// Encode query request.
buf, err := json.Marshal(&postIndexRequest{
Options: opt,
@ -168,7 +167,7 @@ func (c *Client) CreateIndex(ctx context.Context, index string, opt IndexOptions
}
// Create URL & HTTP request.
u := uriPathToURL(c.host, fmt.Sprintf("/index/%s", index))
u := uriPathToURL(c.defaultURI, fmt.Sprintf("/index/%s", index))
req, err := http.NewRequest("POST", u.String(), bytes.NewReader(buf))
if err != nil {
return err
@ -203,9 +202,9 @@ func (c *Client) CreateIndex(ctx context.Context, index string, opt IndexOptions
}
// FragmentNodes returns a list of nodes that own a slice.
func (c *Client) FragmentNodes(ctx context.Context, index string, slice uint64) ([]*Node, error) {
func (c *InternalHTTPClient) FragmentNodes(ctx context.Context, index string, slice uint64) ([]*Node, error) {
// Execute request against the host.
u := uriPathToURL(c.host, "/fragment/nodes")
u := uriPathToURL(c.defaultURI, "/fragment/nodes")
u.RawQuery = (url.Values{"index": {index}, "slice": {strconv.FormatUint(slice, 10)}}).Encode()
// Build request.
@ -234,28 +233,26 @@ func (c *Client) FragmentNodes(ctx context.Context, index string, slice uint64)
}
// ExecuteQuery executes query against index on the server.
func (c *Client) ExecuteQuery(ctx context.Context, index, query string, allowRedirect bool) (result interface{}, err error) {
func (c *InternalHTTPClient) ExecuteQuery(ctx context.Context, index string, queryRequest *internal.QueryRequest) (*internal.QueryResponse, error) {
if index == "" {
return nil, ErrIndexRequired
} else if query == "" {
} else if queryRequest.Query == "" {
return nil, ErrQueryRequired
}
// Encode query request.
buf, err := proto.Marshal(&internal.QueryRequest{
Query: query,
Remote: !allowRedirect,
})
if err != nil {
return nil, fmt.Errorf("marshal: %s", err)
}
// Create URL & HTTP request.
u := uriPathToURL(c.host, fmt.Sprintf("/index/%s/query", index))
req, err := http.NewRequest("POST", u.String(), bytes.NewReader(buf))
// Encode request object.
buf, err := proto.Marshal(queryRequest)
if err != nil {
return nil, err
}
// Create HTTP request.
u := c.clientURI(ctx).Path(fmt.Sprintf("/index/%s/query", index))
req, err := http.NewRequest("POST", u, bytes.NewReader(buf))
if err != nil {
return nil, err
}
req.Header.Set("Content-Length", strconv.Itoa(len(buf)))
req.Header.Set("Content-Type", "application/x-protobuf")
req.Header.Set("Accept", "application/x-protobuf")
@ -276,8 +273,8 @@ func (c *Client) ExecuteQuery(ctx context.Context, index, query string, allowRed
return nil, errors.New(string(body))
}
var qresp internal.QueryResponse
if err := proto.Unmarshal(body, &qresp); err != nil {
qresp := &internal.QueryResponse{}
if err := proto.Unmarshal(body, qresp); err != nil {
return nil, fmt.Errorf("unmarshal response: %s", err)
} else if s := qresp.Err; s != "" {
return nil, errors.New(s)
@ -286,43 +283,15 @@ func (c *Client) ExecuteQuery(ctx context.Context, index, query string, allowRed
return qresp, nil
}
// ExecutePQL executes query string against index on the server.
func (c *Client) ExecutePQL(ctx context.Context, index, query string) (interface{}, error) {
u := uriPathToURL(c.host, "/query")
u.RawQuery = url.Values{"index": {index}}.Encode()
req, err := http.NewRequest("POST", u.String(), bytes.NewReader([]byte(query)))
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", "pilosa/"+Version)
resp, err := c.HTTPClient.Do(req.WithContext(ctx))
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
} else if resp.StatusCode != http.StatusOK {
return nil, errors.New(string(body))
}
return string(body), nil
}
// Import bulk imports bits for a single slice to a host.
func (c *Client) Import(ctx context.Context, index, frame string, slice uint64, bits []Bit) error {
func (c *InternalHTTPClient) Import(ctx context.Context, index, frame string, slice uint64, bits []Bit) error {
if index == "" {
return ErrIndexRequired
} else if frame == "" {
return ErrFrameRequired
}
buf, err := MarshalImportPayload(index, frame, slice, bits)
buf, err := marshalImportPayload(index, frame, slice, bits)
if err != nil {
return fmt.Errorf("Error Creating Payload: %s", err)
}
@ -343,7 +312,7 @@ func (c *Client) Import(ctx context.Context, index, frame string, slice uint64,
return nil
}
func (c *Client) EnsureIndex(ctx context.Context, name string, options IndexOptions) error {
func (c *InternalHTTPClient) EnsureIndex(ctx context.Context, name string, options IndexOptions) error {
err := c.CreateIndex(ctx, name, options)
if err == nil || err == ErrIndexExists {
return nil
@ -351,7 +320,7 @@ func (c *Client) EnsureIndex(ctx context.Context, name string, options IndexOpti
return err
}
func (c *Client) EnsureFrame(ctx context.Context, indexName string, frameName string, options FrameOptions) error {
func (c *InternalHTTPClient) EnsureFrame(ctx context.Context, indexName string, frameName string, options FrameOptions) error {
err := c.CreateFrame(ctx, indexName, frameName, options)
if err == nil || err == ErrFrameExists {
return nil
@ -359,8 +328,8 @@ func (c *Client) EnsureFrame(ctx context.Context, indexName string, frameName st
return err
}
// MarshalImportPayload marshalls the import parameters into a protobuf byte slice.
func MarshalImportPayload(index, frame string, slice uint64, bits []Bit) ([]byte, error) {
// marshalImportPayload marshalls the import parameters into a protobuf byte slice.
func marshalImportPayload(index, frame string, slice uint64, bits []Bit) ([]byte, error) {
// Separate row and column IDs to reduce allocations.
rowIDs := Bits(bits).RowIDs()
columnIDs := Bits(bits).ColumnIDs()
@ -382,7 +351,7 @@ func MarshalImportPayload(index, frame string, slice uint64, bits []Bit) ([]byte
}
// importNode sends a pre-marshaled import request to a node.
func (c *Client) importNode(ctx context.Context, node *Node, buf []byte) error {
func (c *InternalHTTPClient) importNode(ctx context.Context, node *Node, buf []byte) error {
// Create URL & HTTP request.
u := nodePathToURL(node, "/import")
req, err := http.NewRequest("POST", u.String(), bytes.NewReader(buf))
@ -420,14 +389,14 @@ func (c *Client) importNode(ctx context.Context, node *Node, buf []byte) error {
}
// ImportValue bulk imports field values for a single slice to a host.
func (c *Client) ImportValue(ctx context.Context, index, frame, field string, slice uint64, vals []FieldValue) error {
func (c *InternalHTTPClient) ImportValue(ctx context.Context, index, frame, field string, slice uint64, vals []FieldValue) error {
if index == "" {
return ErrIndexRequired
} else if frame == "" {
return ErrFrameRequired
}
buf, err := MarshalImportValuePayload(index, frame, field, slice, vals)
buf, err := marshalImportValuePayload(index, frame, field, slice, vals)
if err != nil {
return fmt.Errorf("Error Creating Payload: %s", err)
}
@ -448,8 +417,8 @@ func (c *Client) ImportValue(ctx context.Context, index, frame, field string, sl
return nil
}
// MarshalImportValuePayload marshalls the import parameters into a protobuf byte slice.
func MarshalImportValuePayload(index, frame, field string, slice uint64, vals []FieldValue) ([]byte, error) {
// marshalImportValuePayload marshalls the import parameters into a protobuf byte slice.
func marshalImportValuePayload(index, frame, field string, slice uint64, vals []FieldValue) ([]byte, error) {
// Separate row and column IDs to reduce allocations.
columnIDs := FieldValues(vals).ColumnIDs()
values := FieldValues(vals).Values()
@ -470,7 +439,7 @@ func MarshalImportValuePayload(index, frame, field string, slice uint64, vals []
}
// importValueNode sends a pre-marshaled import request to a node.
func (c *Client) importValueNode(ctx context.Context, node *Node, buf []byte) error {
func (c *InternalHTTPClient) importValueNode(ctx context.Context, node *Node, buf []byte) error {
// Create URL & HTTP request.
u := nodePathToURL(node, "/import-value")
req, err := http.NewRequest("POST", u.String(), bytes.NewReader(buf))
@ -508,7 +477,7 @@ func (c *Client) importValueNode(ctx context.Context, node *Node, buf []byte) er
}
// ExportCSV bulk exports data for a single slice from a host to CSV format.
func (c *Client) ExportCSV(ctx context.Context, index, frame, view string, slice uint64, w io.Writer) error {
func (c *InternalHTTPClient) ExportCSV(ctx context.Context, index, frame, view string, slice uint64, w io.Writer) error {
if index == "" {
return ErrIndexRequired
} else if frame == "" {
@ -540,7 +509,7 @@ func (c *Client) ExportCSV(ctx context.Context, index, frame, view string, slice
}
// exportNode copies a CSV export from a node to w.
func (c *Client) exportNodeCSV(ctx context.Context, node *Node, index, frame, view string, slice uint64, w io.Writer) error {
func (c *InternalHTTPClient) exportNodeCSV(ctx context.Context, node *Node, index, frame, view string, slice uint64, w io.Writer) error {
// Create URL.
u := nodePathToURL(node, "/export")
u.RawQuery = url.Values{
@ -579,7 +548,7 @@ func (c *Client) exportNodeCSV(ctx context.Context, node *Node, index, frame, vi
}
// BackupTo backs up an entire frame from a cluster to w.
func (c *Client) BackupTo(ctx context.Context, w io.Writer, index, frame, view string) error {
func (c *InternalHTTPClient) BackupTo(ctx context.Context, w io.Writer, index, frame, view string) error {
if index == "" {
return ErrIndexRequired
} else if frame == "" {
@ -620,7 +589,7 @@ func (c *Client) BackupTo(ctx context.Context, w io.Writer, index, frame, view s
}
// backupSliceTo backs up a single slice to tw.
func (c *Client) backupSliceTo(ctx context.Context, tw *tar.Writer, index, frame, view string, slice uint64) error {
func (c *InternalHTTPClient) backupSliceTo(ctx context.Context, tw *tar.Writer, index, frame, view string, slice uint64) error {
// Return error if unable to backup from any slice.
r, err := c.BackupSlice(ctx, index, frame, view, slice)
if err != nil {
@ -658,7 +627,7 @@ func (c *Client) backupSliceTo(ctx context.Context, tw *tar.Writer, index, frame
// BackupSlice retrieves a streaming backup from a single slice.
// This function tries slice owners until one succeeds.
func (c *Client) BackupSlice(ctx context.Context, index, frame, view string, slice uint64) (io.ReadCloser, error) {
func (c *InternalHTTPClient) BackupSlice(ctx context.Context, index, frame, view string, slice uint64) (io.ReadCloser, error) {
// Retrieve a list of nodes that own the slice.
nodes, err := c.FragmentNodes(ctx, index, slice)
if err != nil {
@ -681,7 +650,7 @@ func (c *Client) BackupSlice(ctx context.Context, index, frame, view string, sli
return nil, fmt.Errorf("unable to connect to any owner")
}
func (c *Client) backupSliceNode(ctx context.Context, index, frame, view string, slice uint64, node *Node) (io.ReadCloser, error) {
func (c *InternalHTTPClient) backupSliceNode(ctx context.Context, index, frame, view string, slice uint64, node *Node) (io.ReadCloser, error) {
u := nodePathToURL(node, "/fragment/data")
u.RawQuery = url.Values{
"index": {index},
@ -717,7 +686,7 @@ func (c *Client) backupSliceNode(ctx context.Context, index, frame, view string,
}
// RestoreFrom restores a frame from a backup file to an entire cluster.
func (c *Client) RestoreFrom(ctx context.Context, r io.Reader, index, frame, view string) error {
func (c *InternalHTTPClient) RestoreFrom(ctx context.Context, r io.Reader, index, frame, view string) error {
if index == "" {
return ErrIndexRequired
} else if frame == "" {
@ -756,7 +725,7 @@ func (c *Client) RestoreFrom(ctx context.Context, r io.Reader, index, frame, vie
}
// restoreSliceFrom restores a single slice to all owning nodes.
func (c *Client) restoreSliceFrom(ctx context.Context, buf []byte, index, frame, view string, slice uint64) error {
func (c *InternalHTTPClient) restoreSliceFrom(ctx context.Context, buf []byte, index, frame, view string, slice uint64) error {
// Retrieve a list of nodes that own the slice.
nodes, err := c.FragmentNodes(ctx, index, slice)
if err != nil {
@ -797,7 +766,7 @@ func (c *Client) restoreSliceFrom(ctx context.Context, buf []byte, index, frame,
}
// CreateFrame creates a new frame on the server.
func (c *Client) CreateFrame(ctx context.Context, index, frame string, opt FrameOptions) error {
func (c *InternalHTTPClient) CreateFrame(ctx context.Context, index, frame string, opt FrameOptions) error {
if index == "" {
return ErrIndexRequired
}
@ -811,7 +780,7 @@ func (c *Client) CreateFrame(ctx context.Context, index, frame string, opt Frame
}
// Create URL & HTTP request.
u := uriPathToURL(c.host, fmt.Sprintf("/index/%s/frame/%s", index, frame))
u := uriPathToURL(c.defaultURI, fmt.Sprintf("/index/%s/frame/%s", index, frame))
req, err := http.NewRequest("POST", u.String(), bytes.NewReader(buf))
if err != nil {
return err
@ -846,8 +815,8 @@ func (c *Client) CreateFrame(ctx context.Context, index, frame string, opt Frame
}
// RestoreFrame restores an entire frame from a host in another cluster.
func (c *Client) RestoreFrame(ctx context.Context, host, index, frame string) error {
u := uriPathToURL(c.host, fmt.Sprintf("/index/%s/frame/%s/restore", index, frame))
func (c *InternalHTTPClient) RestoreFrame(ctx context.Context, host, index, frame string) error {
u := uriPathToURL(c.defaultURI, fmt.Sprintf("/index/%s/frame/%s/restore", index, frame))
u.RawQuery = url.Values{
"host": {host},
}.Encode()
@ -876,9 +845,9 @@ func (c *Client) RestoreFrame(ctx context.Context, host, index, frame string) er
}
// FrameViews returns a list of view names for a frame.
func (c *Client) FrameViews(ctx context.Context, index, frame string) ([]string, error) {
func (c *InternalHTTPClient) FrameViews(ctx context.Context, index, frame string) ([]string, error) {
// Create URL & HTTP request.
u := uriPathToURL(c.host, fmt.Sprintf("/index/%s/frame/%s/views", index, frame))
u := uriPathToURL(c.defaultURI, fmt.Sprintf("/index/%s/frame/%s/views", index, frame))
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
return nil, err
@ -913,8 +882,8 @@ func (c *Client) FrameViews(ctx context.Context, index, frame string) ([]string,
// FragmentBlocks returns a list of block checksums for a fragment on a host.
// Only returns blocks which contain data.
func (c *Client) FragmentBlocks(ctx context.Context, index, frame, view string, slice uint64) ([]FragmentBlock, error) {
u := uriPathToURL(c.host, "/fragment/blocks")
func (c *InternalHTTPClient) FragmentBlocks(ctx context.Context, index, frame, view string, slice uint64) ([]FragmentBlock, error) {
u := uriPathToURL(c.defaultURI, "/fragment/blocks")
u.RawQuery = url.Values{
"index": {index},
"frame": {frame},
@ -955,7 +924,7 @@ func (c *Client) FragmentBlocks(ctx context.Context, index, frame, view string,
}
// BlockData returns row/column id pairs for a block.
func (c *Client) BlockData(ctx context.Context, index, frame, view string, slice uint64, block int) ([]uint64, []uint64, error) {
func (c *InternalHTTPClient) BlockData(ctx context.Context, index, frame, view string, slice uint64, block int) ([]uint64, []uint64, error) {
buf, err := proto.Marshal(&internal.BlockDataRequest{
Index: index,
Frame: frame,
@ -967,7 +936,7 @@ func (c *Client) BlockData(ctx context.Context, index, frame, view string, slice
return nil, nil, err
}
u := uriPathToURL(c.host, "/fragment/block/data")
u := uriPathToURL(c.defaultURI, "/fragment/block/data")
req, err := http.NewRequest("GET", u.String(), bytes.NewReader(buf))
if err != nil {
return nil, nil, err
@ -1003,8 +972,8 @@ func (c *Client) BlockData(ctx context.Context, index, frame, view string, slice
}
// ColumnAttrDiff returns data from differing blocks on a remote host.
func (c *Client) ColumnAttrDiff(ctx context.Context, index string, blks []AttrBlock) (map[uint64]map[string]interface{}, error) {
u := uriPathToURL(c.host, fmt.Sprintf("/index/%s/attr/diff", index))
func (c *InternalHTTPClient) ColumnAttrDiff(ctx context.Context, index string, blks []AttrBlock) (map[uint64]map[string]interface{}, error) {
u := uriPathToURL(c.defaultURI, fmt.Sprintf("/index/%s/attr/diff", index))
// Encode request.
buf, err := json.Marshal(postIndexAttrDiffRequest{Blocks: blks})
@ -1043,8 +1012,8 @@ func (c *Client) ColumnAttrDiff(ctx context.Context, index string, blks []AttrBl
}
// RowAttrDiff returns data from differing blocks on a remote host.
func (c *Client) RowAttrDiff(ctx context.Context, index, frame string, blks []AttrBlock) (map[uint64]map[string]interface{}, error) {
u := uriPathToURL(c.host, fmt.Sprintf("/index/%s/frame/%s/attr/diff", index, frame))
func (c *InternalHTTPClient) RowAttrDiff(ctx context.Context, index, frame string, blks []AttrBlock) (map[uint64]map[string]interface{}, error) {
u := uriPathToURL(c.defaultURI, fmt.Sprintf("/index/%s/frame/%s/attr/diff", index, frame))
// Encode request.
buf, err := json.Marshal(postFrameAttrDiffRequest{Blocks: blks})
@ -1084,6 +1053,14 @@ func (c *Client) RowAttrDiff(ctx context.Context, index, frame string, blks []At
return rsp.Attrs, nil
}
func (c *InternalHTTPClient) clientURI(ctx context.Context) *URI {
clientURI := c.defaultURI
if contextURI, ok := ctx.Value("uri").(*URI); ok {
clientURI = contextURI
}
return clientURI
}
// Bit represents the location of a single bit.
type Bit struct {
RowID uint64
@ -1229,3 +1206,33 @@ func nodePathToURL(node *Node, path string) url.URL {
Path: path,
}
}
// InternalClient should be implemented by any struct that enables any transport between nodes
// TODO: Refactor
// Note from Travis: Typically an interface containing more than two or three methods is an indication that
// something hasn't been architected correctly.
// While I understand that putting the entire Client behind an interface might require this many methods,
// I don't want to let it go unquestioned.
type InternalClient interface {
MaxSliceByIndex(ctx context.Context) (map[string]uint64, error)
MaxInverseSliceByIndex(ctx context.Context) (map[string]uint64, error)
Schema(ctx context.Context) ([]*IndexInfo, error)
CreateIndex(ctx context.Context, index string, opt IndexOptions) error
FragmentNodes(ctx context.Context, index string, slice uint64) ([]*Node, error)
ExecuteQuery(ctx context.Context, index string, queryRequest *internal.QueryRequest) (*internal.QueryResponse, error)
Import(ctx context.Context, index, frame string, slice uint64, bits []Bit) error
EnsureIndex(ctx context.Context, name string, options IndexOptions) error
EnsureFrame(ctx context.Context, indexName string, frameName string, options FrameOptions) error
ImportValue(ctx context.Context, index, frame, field string, slice uint64, vals []FieldValue) error
ExportCSV(ctx context.Context, index, frame, view string, slice uint64, w io.Writer) error
BackupTo(ctx context.Context, w io.Writer, index, frame, view string) error
BackupSlice(ctx context.Context, index, frame, view string, slice uint64) (io.ReadCloser, error)
RestoreFrom(ctx context.Context, r io.Reader, index, frame, view string) error
CreateFrame(ctx context.Context, index, frame string, opt FrameOptions) error
RestoreFrame(ctx context.Context, host, index, frame string) error
FrameViews(ctx context.Context, index, frame string) ([]string, error)
FragmentBlocks(ctx context.Context, index, frame, view string, slice uint64) ([]FragmentBlock, error)
BlockData(ctx context.Context, index, frame, view string, slice uint64, block int) ([]uint64, []uint64, error)
ColumnAttrDiff(ctx context.Context, index string, blks []AttrBlock) (map[uint64]map[string]interface{}, error)
RowAttrDiff(ctx context.Context, index, frame string, blks []AttrBlock) (map[uint64]map[string]interface{}, error)
}

View file

@ -140,15 +140,17 @@ func TestClient_MultiNode(t *testing.T) {
client[2] = test.MustNewClient(s[2].Host())
topN := 4
q := fmt.Sprintf(`TopN(frame="%s", n=%d)`, "f", topN)
result, err := client[0].ExecuteQuery(context.Background(), "i", q, true)
queryRequest := &internal.QueryRequest{
Query: fmt.Sprintf(`TopN(frame="%s", n=%d)`, "f", topN),
Remote: false,
}
result, err := client[0].ExecuteQuery(context.Background(), "i", queryRequest)
if err != nil {
t.Fatal(err)
}
// Check the results before every node has the correct max slice value.
pairs := result.(internal.QueryResponse).Results[0].Pairs
pairs := result.Results[0].Pairs
for _, pair := range pairs {
if pair.Key == 22 && pair.Count != 3 {
t.Fatalf("Invalid Cluster wide MaxSlice prevents accurate calculation of %s", pair)
@ -160,13 +162,13 @@ func TestClient_MultiNode(t *testing.T) {
hldr[1].Index("i").SetRemoteMaxSlice(maxSlice)
hldr[2].Index("i").SetRemoteMaxSlice(maxSlice)
result, err = client[0].ExecuteQuery(context.Background(), "i", q, true)
result, err = client[0].ExecuteQuery(context.Background(), "i", queryRequest)
if err != nil {
t.Fatal(err)
}
// Test must return exactly N results.
if len(result.(internal.QueryResponse).Results[0].Pairs) != topN {
if len(result.Results[0].Pairs) != topN {
t.Fatalf("unexpected number of TopN results: %s", spew.Sdump(result))
}
p := []*internal.Pair{
@ -176,15 +178,15 @@ func TestClient_MultiNode(t *testing.T) {
{Key: 99, Count: 7}}
// Valdidate the Top 4 result counts.
if !reflect.DeepEqual(result.(internal.QueryResponse).Results[0].Pairs, p) {
if !reflect.DeepEqual(result.Results[0].Pairs, p) {
t.Fatalf("Invalid TopN result set: %s", spew.Sdump(result))
}
result1, err := client[1].ExecuteQuery(context.Background(), "i", q, true)
result1, err := client[1].ExecuteQuery(context.Background(), "i", queryRequest)
if err != nil {
t.Fatal(err)
}
result2, err := client[2].ExecuteQuery(context.Background(), "i", q, true)
result2, err := client[2].ExecuteQuery(context.Background(), "i", queryRequest)
if err != nil {
t.Fatal(err)
}

View file

@ -23,6 +23,7 @@ import (
"time"
"github.com/pilosa/pilosa"
"github.com/pilosa/pilosa/internal"
)
// BenchCommand represents a command for benchmarking index operations.
@ -70,7 +71,7 @@ func (cmd *BenchCommand) Run(ctx context.Context) error {
}
// runSetBit executes a benchmark of random SetBit() operations.
func (cmd *BenchCommand) runSetBit(ctx context.Context, client *pilosa.Client) error {
func (cmd *BenchCommand) runSetBit(ctx context.Context, client pilosa.InternalClient) error {
if cmd.N == 0 {
return errors.New("operation count required")
} else if cmd.Index == "" {
@ -89,9 +90,11 @@ func (cmd *BenchCommand) runSetBit(ctx context.Context, client *pilosa.Client) e
rowID := rand.Intn(maxRowID)
columnID := rand.Intn(maxColumnID)
q := fmt.Sprintf(`SetBit(id=%d, frame="%s", columnID=%d)`, rowID, cmd.Frame, columnID)
if _, err := client.ExecuteQuery(ctx, cmd.Index, q, true); err != nil {
queryRequest := &internal.QueryRequest{
Query: fmt.Sprintf(`SetBit(id=%d, frame="%s", columnID=%d)`, rowID, cmd.Frame, columnID),
Remote: false,
}
if _, err := client.ExecuteQuery(ctx, cmd.Index, queryRequest); err != nil {
return err
}
}

View file

@ -19,8 +19,8 @@ func SetTLSConfig(flags *pflag.FlagSet, certificatePath *string, certificateKeyP
flags.BoolVarP(skipVerify, "tls.skip-verify", "", false, "Skip TLS certificate verification (not secure)")
}
// CommandClient returns a pilosa.Client for the command
func CommandClient(cmd CommandWithTLSSupport) (*pilosa.Client, error) {
// CommandClient returns a pilosa.InternalHTTPClient for the command
func CommandClient(cmd CommandWithTLSSupport) (*pilosa.InternalHTTPClient, error) {
tlsConfig := cmd.TLSConfiguration()
var clientOptions *pilosa.ClientOptions
if tlsConfig.CertificatePath != "" && tlsConfig.CertificateKeyPath != "" {
@ -34,7 +34,7 @@ func CommandClient(cmd CommandWithTLSSupport) (*pilosa.Client, error) {
}
clientOptions = &pilosa.ClientOptions{TLS: TLSConfig}
}
client, err := pilosa.NewClient(cmd.TLSHost(), clientOptions)
client, err := pilosa.NewInternalHTTPClient(cmd.TLSHost(), clientOptions)
if err != nil {
return nil, err
}

View file

@ -58,7 +58,7 @@ type ImportCommand struct {
Sort bool `json:"sort"`
// Reusable client.
Client *pilosa.Client `json:"-"`
Client pilosa.InternalClient `json:"-"`
// Standard input/output
*pilosa.CmdIO

View file

@ -15,16 +15,12 @@
package pilosa
import (
"bytes"
"context"
"errors"
"fmt"
"io/ioutil"
"net/http"
"sort"
"time"
"github.com/gogo/protobuf/proto"
"github.com/pilosa/pilosa/internal"
"github.com/pilosa/pilosa/pql"
)
@ -47,8 +43,8 @@ type Executor struct {
Host string
Cluster *Cluster
// Client used for remote HTTP requests.
HTTPClient *http.Client
// Client used for remote requests.
client InternalClient
// Maximum number of SetBit() or ClearBit() commands per request.
MaxWritesPerRequest int
@ -59,13 +55,8 @@ func NewExecutor(clientOptions *ClientOptions) *Executor {
if clientOptions == nil {
clientOptions = &ClientOptions{}
}
transport := &http.Transport{}
if clientOptions.TLS != nil {
transport.TLSClientConfig = clientOptions.TLS
}
client := &http.Client{Transport: transport}
return &Executor{
HTTPClient: client,
client: NewInternalHTTPClientFromURI(nil, clientOptions),
}
}
@ -1377,48 +1368,17 @@ func (e *Executor) exec(ctx context.Context, node *Node, index string, q *pql.Qu
Slices: slices,
Remote: true,
}
buf, err := proto.Marshal(pbreq)
uri, err := NewURIFromAddress(node.Host)
if err != nil {
return nil, err
}
// Create HTTP request.
u := nodePathToURL(node, fmt.Sprintf("/index/%s/query", index))
u.Scheme = e.Scheme
req, err := http.NewRequest("POST", (&u).String(), bytes.NewReader(buf))
uri.SetScheme(node.Scheme)
ctx = context.WithValue(ctx, "uri", uri)
pb, err := e.client.ExecuteQuery(ctx, index, pbreq)
if err != nil {
return nil, err
}
// Require protobuf encoding.
req.Header.Set("Accept", "application/x-protobuf")
req.Header.Set("Content-Type", "application/x-protobuf")
req.Header.Set("User-Agent", "pilosa/"+Version)
// Send request to remote node.
resp, err := e.HTTPClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// Read response into buffer.
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// Check status code.
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("invalid status Executor.exec: code=%d, err=%s, req: %v", resp.StatusCode, body, req)
}
// Decode response object.
var pb internal.QueryResponse
if err := proto.Unmarshal(body, &pb); err != nil {
return nil, err
}
// Return an error, if specified on response.
if err := decodeError(pb.Err); err != nil {
return nil, err

View file

@ -1714,7 +1714,7 @@ func (s *FragmentSyncer) SyncFragment() error {
}
// Retrieve remote blocks.
client, err := NewClient(node.Host, s.ClientOptions)
client, err := NewInternalHTTPClient(node.Host, s.ClientOptions)
if err != nil {
return err
}
@ -1782,7 +1782,7 @@ func (s *FragmentSyncer) syncBlock(id int) error {
// Read pairs from each remote block.
var pairSets []PairSet
var clients []*Client
var clients []InternalClient
for _, node := range s.Cluster.FragmentNodes(f.Index(), f.Slice()) {
if s.Host == node.Host {
continue
@ -1793,7 +1793,7 @@ func (s *FragmentSyncer) syncBlock(id int) error {
return nil
}
client, err := NewClient(node.Host, s.ClientOptions)
client, err := NewInternalHTTPClient(node.Host, s.ClientOptions)
if err != nil {
return err
}
@ -1848,7 +1848,11 @@ func (s *FragmentSyncer) syncBlock(id int) error {
}
// Execute query.
_, err := clients[i].ExecuteQuery(context.Background(), f.Index(), buf.String(), false)
queryRequest := &internal.QueryRequest{
Query: buf.String(),
Remote: true,
}
_, err := clients[i].ExecuteQuery(context.Background(), f.Index(), queryRequest)
if err != nil {
return err
}

View file

@ -1506,11 +1506,7 @@ func (h *Handler) handlePostFrameRestore(w http.ResponseWriter, r *http.Request)
}
// Create a client for the remote cluster.
client, err := NewClientFromURI(host, h.ClientOptions)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
client := NewInternalHTTPClientFromURI(host, h.ClientOptions)
// Determine the maximum number of slices.
maxSlices, err := client.MaxSliceByIndex(r.Context())

View file

@ -515,7 +515,7 @@ func (s *HolderSyncer) syncIndex(index string) error {
// Sync with every other host.
for _, node := range Nodes(s.Cluster.Nodes).FilterHost(s.URI.HostPort()) {
client, err := NewClient(node.Host, s.ClientOptions)
client, err := NewInternalHTTPClient(node.Host, s.ClientOptions)
if err != nil {
return err
}
@ -560,7 +560,7 @@ func (s *HolderSyncer) syncFrame(index, name string) error {
// Sync with every other host.
for _, node := range Nodes(s.Cluster.Nodes).FilterHost(s.URI.HostPort()) {
client, err := NewClient(node.Host, s.ClientOptions)
client, err := NewInternalHTTPClient(node.Host, s.ClientOptions)
if err != nil {
return err
}

File diff suppressed because it is too large Load diff

View file

@ -116,6 +116,7 @@ message NodeStatus {
string Host = 1;
string State = 2;
repeated Index Indexes = 3;
string Scheme = 4;
}
message ClusterStatus {

View file

@ -1,6 +1,5 @@
// Code generated by protoc-gen-gogo.
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: public.proto
// DO NOT EDIT!
/*
Package internal is a generated protocol buffer package.
@ -28,6 +27,8 @@ import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import encoding_binary "encoding/binary"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
@ -51,6 +52,13 @@ func (m *Bitmap) String() string { return proto.CompactTextString(m)
func (*Bitmap) ProtoMessage() {}
func (*Bitmap) Descriptor() ([]byte, []int) { return fileDescriptorPublic, []int{0} }
func (m *Bitmap) GetBits() []uint64 {
if m != nil {
return m.Bits
}
return nil
}
func (m *Bitmap) GetAttrs() []*Attr {
if m != nil {
return m.Attrs
@ -68,6 +76,20 @@ func (m *Pair) String() string { return proto.CompactTextString(m) }
func (*Pair) ProtoMessage() {}
func (*Pair) Descriptor() ([]byte, []int) { return fileDescriptorPublic, []int{1} }
func (m *Pair) GetKey() uint64 {
if m != nil {
return m.Key
}
return 0
}
func (m *Pair) GetCount() uint64 {
if m != nil {
return m.Count
}
return 0
}
type SumCount struct {
Sum int64 `protobuf:"varint,1,opt,name=Sum,proto3" json:"Sum,omitempty"`
Count int64 `protobuf:"varint,2,opt,name=Count,proto3" json:"Count,omitempty"`
@ -78,6 +100,20 @@ func (m *SumCount) String() string { return proto.CompactTextString(m
func (*SumCount) ProtoMessage() {}
func (*SumCount) Descriptor() ([]byte, []int) { return fileDescriptorPublic, []int{2} }
func (m *SumCount) GetSum() int64 {
if m != nil {
return m.Sum
}
return 0
}
func (m *SumCount) GetCount() int64 {
if m != nil {
return m.Count
}
return 0
}
type Bit struct {
RowID uint64 `protobuf:"varint,1,opt,name=RowID,proto3" json:"RowID,omitempty"`
ColumnID uint64 `protobuf:"varint,2,opt,name=ColumnID,proto3" json:"ColumnID,omitempty"`
@ -89,6 +125,27 @@ func (m *Bit) String() string { return proto.CompactTextString(m) }
func (*Bit) ProtoMessage() {}
func (*Bit) Descriptor() ([]byte, []int) { return fileDescriptorPublic, []int{3} }
func (m *Bit) GetRowID() uint64 {
if m != nil {
return m.RowID
}
return 0
}
func (m *Bit) GetColumnID() uint64 {
if m != nil {
return m.ColumnID
}
return 0
}
func (m *Bit) GetTimestamp() int64 {
if m != nil {
return m.Timestamp
}
return 0
}
type ColumnAttrSet struct {
ID uint64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
Attrs []*Attr `protobuf:"bytes,2,rep,name=Attrs" json:"Attrs,omitempty"`
@ -99,6 +156,13 @@ func (m *ColumnAttrSet) String() string { return proto.CompactTextStr
func (*ColumnAttrSet) ProtoMessage() {}
func (*ColumnAttrSet) Descriptor() ([]byte, []int) { return fileDescriptorPublic, []int{4} }
func (m *ColumnAttrSet) GetID() uint64 {
if m != nil {
return m.ID
}
return 0
}
func (m *ColumnAttrSet) GetAttrs() []*Attr {
if m != nil {
return m.Attrs
@ -120,6 +184,48 @@ func (m *Attr) String() string { return proto.CompactTextString(m) }
func (*Attr) ProtoMessage() {}
func (*Attr) Descriptor() ([]byte, []int) { return fileDescriptorPublic, []int{5} }
func (m *Attr) GetKey() string {
if m != nil {
return m.Key
}
return ""
}
func (m *Attr) GetType() uint64 {
if m != nil {
return m.Type
}
return 0
}
func (m *Attr) GetStringValue() string {
if m != nil {
return m.StringValue
}
return ""
}
func (m *Attr) GetIntValue() int64 {
if m != nil {
return m.IntValue
}
return 0
}
func (m *Attr) GetBoolValue() bool {
if m != nil {
return m.BoolValue
}
return false
}
func (m *Attr) GetFloatValue() float64 {
if m != nil {
return m.FloatValue
}
return 0
}
type AttrMap struct {
Attrs []*Attr `protobuf:"bytes,1,rep,name=Attrs" json:"Attrs,omitempty"`
}
@ -150,6 +256,48 @@ func (m *QueryRequest) String() string { return proto.CompactTextStri
func (*QueryRequest) ProtoMessage() {}
func (*QueryRequest) Descriptor() ([]byte, []int) { return fileDescriptorPublic, []int{7} }
func (m *QueryRequest) GetQuery() string {
if m != nil {
return m.Query
}
return ""
}
func (m *QueryRequest) GetSlices() []uint64 {
if m != nil {
return m.Slices
}
return nil
}
func (m *QueryRequest) GetColumnAttrs() bool {
if m != nil {
return m.ColumnAttrs
}
return false
}
func (m *QueryRequest) GetRemote() bool {
if m != nil {
return m.Remote
}
return false
}
func (m *QueryRequest) GetExcludeAttrs() bool {
if m != nil {
return m.ExcludeAttrs
}
return false
}
func (m *QueryRequest) GetExcludeBits() bool {
if m != nil {
return m.ExcludeBits
}
return false
}
type QueryResponse struct {
Err string `protobuf:"bytes,1,opt,name=Err,proto3" json:"Err,omitempty"`
Results []*QueryResult `protobuf:"bytes,2,rep,name=Results" json:"Results,omitempty"`
@ -161,6 +309,13 @@ func (m *QueryResponse) String() string { return proto.CompactTextStr
func (*QueryResponse) ProtoMessage() {}
func (*QueryResponse) Descriptor() ([]byte, []int) { return fileDescriptorPublic, []int{8} }
func (m *QueryResponse) GetErr() string {
if m != nil {
return m.Err
}
return ""
}
func (m *QueryResponse) GetResults() []*QueryResult {
if m != nil {
return m.Results
@ -195,6 +350,13 @@ func (m *QueryResult) GetBitmap() *Bitmap {
return nil
}
func (m *QueryResult) GetN() uint64 {
if m != nil {
return m.N
}
return 0
}
func (m *QueryResult) GetPairs() []*Pair {
if m != nil {
return m.Pairs
@ -209,6 +371,13 @@ func (m *QueryResult) GetSumCount() *SumCount {
return nil
}
func (m *QueryResult) GetChanged() bool {
if m != nil {
return m.Changed
}
return false
}
type ImportRequest struct {
Index string `protobuf:"bytes,1,opt,name=Index,proto3" json:"Index,omitempty"`
Frame string `protobuf:"bytes,2,opt,name=Frame,proto3" json:"Frame,omitempty"`
@ -223,6 +392,48 @@ func (m *ImportRequest) String() string { return proto.CompactTextStr
func (*ImportRequest) ProtoMessage() {}
func (*ImportRequest) Descriptor() ([]byte, []int) { return fileDescriptorPublic, []int{10} }
func (m *ImportRequest) GetIndex() string {
if m != nil {
return m.Index
}
return ""
}
func (m *ImportRequest) GetFrame() string {
if m != nil {
return m.Frame
}
return ""
}
func (m *ImportRequest) GetSlice() uint64 {
if m != nil {
return m.Slice
}
return 0
}
func (m *ImportRequest) GetRowIDs() []uint64 {
if m != nil {
return m.RowIDs
}
return nil
}
func (m *ImportRequest) GetColumnIDs() []uint64 {
if m != nil {
return m.ColumnIDs
}
return nil
}
func (m *ImportRequest) GetTimestamps() []int64 {
if m != nil {
return m.Timestamps
}
return nil
}
type ImportValueRequest struct {
Index string `protobuf:"bytes,1,opt,name=Index,proto3" json:"Index,omitempty"`
Frame string `protobuf:"bytes,2,opt,name=Frame,proto3" json:"Frame,omitempty"`
@ -237,6 +448,48 @@ func (m *ImportValueRequest) String() string { return proto.CompactTe
func (*ImportValueRequest) ProtoMessage() {}
func (*ImportValueRequest) Descriptor() ([]byte, []int) { return fileDescriptorPublic, []int{11} }
func (m *ImportValueRequest) GetIndex() string {
if m != nil {
return m.Index
}
return ""
}
func (m *ImportValueRequest) GetFrame() string {
if m != nil {
return m.Frame
}
return ""
}
func (m *ImportValueRequest) GetSlice() uint64 {
if m != nil {
return m.Slice
}
return 0
}
func (m *ImportValueRequest) GetField() string {
if m != nil {
return m.Field
}
return ""
}
func (m *ImportValueRequest) GetColumnIDs() []uint64 {
if m != nil {
return m.ColumnIDs
}
return nil
}
func (m *ImportValueRequest) GetValues() []uint64 {
if m != nil {
return m.Values
}
return nil
}
func init() {
proto.RegisterType((*Bitmap)(nil), "internal.Bitmap")
proto.RegisterType((*Pair)(nil), "internal.Pair")
@ -472,7 +725,8 @@ func (m *Attr) MarshalTo(dAtA []byte) (int, error) {
if m.FloatValue != 0 {
dAtA[i] = 0x31
i++
i = encodeFixed64Public(dAtA, i, uint64(math.Float64bits(float64(m.FloatValue))))
encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.FloatValue))))
i += 8
}
return i, nil
}
@ -863,24 +1117,6 @@ func (m *ImportValueRequest) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func encodeFixed64Public(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
dAtA[offset+4] = uint8(v >> 32)
dAtA[offset+5] = uint8(v >> 40)
dAtA[offset+6] = uint8(v >> 48)
dAtA[offset+7] = uint8(v >> 56)
return offset + 8
}
func encodeFixed32Public(dAtA []byte, offset int, v uint32) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
return offset + 4
}
func encodeVarintPublic(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
@ -1194,7 +1430,24 @@ func (m *Bitmap) Unmarshal(dAtA []byte) error {
}
switch fieldNum {
case 1:
if wireType == 2 {
if wireType == 0 {
var v uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPublic
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Bits = append(m.Bits, v)
} else if wireType == 2 {
var packedLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
@ -1235,23 +1488,6 @@ func (m *Bitmap) Unmarshal(dAtA []byte) error {
}
m.Bits = append(m.Bits, v)
}
} else if wireType == 0 {
var v uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPublic
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Bits = append(m.Bits, v)
} else {
return fmt.Errorf("proto: wrong wireType = %d for field Bits", wireType)
}
@ -1843,15 +2079,8 @@ func (m *Attr) Unmarshal(dAtA []byte) error {
if (iNdEx + 8) > l {
return io.ErrUnexpectedEOF
}
v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:]))
iNdEx += 8
v = uint64(dAtA[iNdEx-8])
v |= uint64(dAtA[iNdEx-7]) << 8
v |= uint64(dAtA[iNdEx-6]) << 16
v |= uint64(dAtA[iNdEx-5]) << 24
v |= uint64(dAtA[iNdEx-4]) << 32
v |= uint64(dAtA[iNdEx-3]) << 40
v |= uint64(dAtA[iNdEx-2]) << 48
v |= uint64(dAtA[iNdEx-1]) << 56
m.FloatValue = float64(math.Float64frombits(v))
default:
iNdEx = preIndex
@ -2014,7 +2243,24 @@ func (m *QueryRequest) Unmarshal(dAtA []byte) error {
m.Query = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType == 2 {
if wireType == 0 {
var v uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPublic
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Slices = append(m.Slices, v)
} else if wireType == 2 {
var packedLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
@ -2055,23 +2301,6 @@ func (m *QueryRequest) Unmarshal(dAtA []byte) error {
}
m.Slices = append(m.Slices, v)
}
} else if wireType == 0 {
var v uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPublic
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Slices = append(m.Slices, v)
} else {
return fmt.Errorf("proto: wrong wireType = %d for field Slices", wireType)
}
@ -2610,7 +2839,24 @@ func (m *ImportRequest) Unmarshal(dAtA []byte) error {
}
}
case 4:
if wireType == 2 {
if wireType == 0 {
var v uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPublic
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.RowIDs = append(m.RowIDs, v)
} else if wireType == 2 {
var packedLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
@ -2651,7 +2897,11 @@ func (m *ImportRequest) Unmarshal(dAtA []byte) error {
}
m.RowIDs = append(m.RowIDs, v)
}
} else if wireType == 0 {
} else {
return fmt.Errorf("proto: wrong wireType = %d for field RowIDs", wireType)
}
case 5:
if wireType == 0 {
var v uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
@ -2667,12 +2917,8 @@ func (m *ImportRequest) Unmarshal(dAtA []byte) error {
break
}
}
m.RowIDs = append(m.RowIDs, v)
} else {
return fmt.Errorf("proto: wrong wireType = %d for field RowIDs", wireType)
}
case 5:
if wireType == 2 {
m.ColumnIDs = append(m.ColumnIDs, v)
} else if wireType == 2 {
var packedLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
@ -2713,8 +2959,12 @@ func (m *ImportRequest) Unmarshal(dAtA []byte) error {
}
m.ColumnIDs = append(m.ColumnIDs, v)
}
} else if wireType == 0 {
var v uint64
} else {
return fmt.Errorf("proto: wrong wireType = %d for field ColumnIDs", wireType)
}
case 6:
if wireType == 0 {
var v int64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPublic
@ -2724,17 +2974,13 @@ func (m *ImportRequest) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
v |= (uint64(b) & 0x7F) << shift
v |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.ColumnIDs = append(m.ColumnIDs, v)
} else {
return fmt.Errorf("proto: wrong wireType = %d for field ColumnIDs", wireType)
}
case 6:
if wireType == 2 {
m.Timestamps = append(m.Timestamps, v)
} else if wireType == 2 {
var packedLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
@ -2775,23 +3021,6 @@ func (m *ImportRequest) Unmarshal(dAtA []byte) error {
}
m.Timestamps = append(m.Timestamps, v)
}
} else if wireType == 0 {
var v int64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPublic
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Timestamps = append(m.Timestamps, v)
} else {
return fmt.Errorf("proto: wrong wireType = %d for field Timestamps", wireType)
}
@ -2952,7 +3181,24 @@ func (m *ImportValueRequest) Unmarshal(dAtA []byte) error {
m.Field = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 5:
if wireType == 2 {
if wireType == 0 {
var v uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPublic
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.ColumnIDs = append(m.ColumnIDs, v)
} else if wireType == 2 {
var packedLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
@ -2993,7 +3239,11 @@ func (m *ImportValueRequest) Unmarshal(dAtA []byte) error {
}
m.ColumnIDs = append(m.ColumnIDs, v)
}
} else if wireType == 0 {
} else {
return fmt.Errorf("proto: wrong wireType = %d for field ColumnIDs", wireType)
}
case 6:
if wireType == 0 {
var v uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
@ -3009,12 +3259,8 @@ func (m *ImportValueRequest) Unmarshal(dAtA []byte) error {
break
}
}
m.ColumnIDs = append(m.ColumnIDs, v)
} else {
return fmt.Errorf("proto: wrong wireType = %d for field ColumnIDs", wireType)
}
case 6:
if wireType == 2 {
m.Values = append(m.Values, v)
} else if wireType == 2 {
var packedLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
@ -3055,23 +3301,6 @@ func (m *ImportValueRequest) Unmarshal(dAtA []byte) error {
}
m.Values = append(m.Values, v)
}
} else if wireType == 0 {
var v uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPublic
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Values = append(m.Values, v)
} else {
return fmt.Errorf("proto: wrong wireType = %d for field Values", wireType)
}

View file

@ -19,7 +19,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
@ -35,6 +34,7 @@ import (
"github.com/CAFxX/gcnotifier"
"github.com/gogo/protobuf/proto"
"github.com/pilosa/pilosa/internal"
"golang.org/x/net/context"
)
// Default server settings.
@ -76,7 +76,7 @@ type Server struct {
LogOutput io.Writer
defaultClient *http.Client
defaultClient InternalClient
}
// NewServer returns a new instance of Server.
@ -386,6 +386,7 @@ func (s *Server) LocalStatus() (proto.Message, error) {
}
ns := internal.NodeStatus{
Scheme: s.URI.Scheme(),
Host: s.URI.HostPort(),
State: NodeStateUp,
Indexes: EncodeIndexes(s.Holder.Indexes()),
@ -480,31 +481,13 @@ func (s *Server) checkMaxSlices(scheme string, hostPort string) (map[string]uint
req.Header.Set("Content-Type", "application/x-protobuf")
req.Header.Set("User-Agent", "pilosa/"+Version)
resp, err := s.defaultClient.Do(req)
nodeURI, err := NewURIFromAddress(hostPort)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// Read response into buffer.
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// Check status code.
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("invalid status checkMaxSlices: code=%d, err=%s, req=%v", resp.StatusCode, body, req)
}
// Decode response object.
pb := internal.MaxSlicesResponse{}
if err = proto.Unmarshal(body, &pb); err != nil {
return nil, err
}
return pb.MaxSlices, nil
nodeURI.SetScheme(scheme)
ctx := context.WithValue(context.Background(), "uri", nodeURI)
return s.defaultClient.MaxSliceByIndex(ctx)
}
// monitorRuntime periodically polls the Go runtime metrics.
@ -555,7 +538,7 @@ func (s *Server) createDefaultClient() {
if s.TLS != nil {
transport.TLSClientConfig = s.TLS
}
s.defaultClient = &http.Client{Transport: transport}
s.defaultClient = NewInternalHTTPClientFromURI(nil, &ClientOptions{TLS: s.TLS})
}
// CountOpenFiles on opperating systems that support lsof

View file

@ -53,7 +53,7 @@ func TestMain_Set_Quick(t *testing.T) {
defer m.Close()
// Create client.
client, err := pilosa.NewClient(m.Server.URI.HostPort(), nil)
client, err := pilosa.NewInternalHTTPClient(m.Server.URI.HostPort(), nil)
if err != nil {
t.Fatal(err)
}
@ -326,7 +326,7 @@ func TestMain_FrameRestore(t *testing.T) {
defer m2.Close()
// Import from first cluster.
client, err := pilosa.NewClient(m2.Server.URI.HostPort(), nil)
client, err := pilosa.NewInternalHTTPClient(m2.Server.URI.HostPort(), nil)
if err != nil {
t.Fatal(err)
} else if err := m2.Client().CreateIndex(context.Background(), "i", pilosa.IndexOptions{}); err != nil && err != pilosa.ErrIndexExists {
@ -696,8 +696,8 @@ func (m *Main) Reopen() error {
func (m *Main) URL() string { return "http://" + m.Server.Addr().String() }
// Client returns a client to connect to the program.
func (m *Main) Client() *pilosa.Client {
client, err := pilosa.NewClient(m.Server.URI.HostPort(), nil)
func (m *Main) Client() *pilosa.InternalHTTPClient {
client, err := pilosa.NewInternalHTTPClient(m.Server.URI.HostPort(), nil)
if err != nil {
panic(err)
}

View file

@ -6,14 +6,14 @@ import (
// Client represents a test wrapper for pilosa.Client.
type Client struct {
*pilosa.Client
*pilosa.InternalHTTPClient
}
// MustNewClient returns a new instance of Client. Panic on error.
func MustNewClient(host string) *Client {
c, err := pilosa.NewClient(host, nil)
c, err := pilosa.NewInternalHTTPClient(host, nil)
if err != nil {
panic(err)
}
return &Client{Client: c}
return &Client{InternalHTTPClient: c}
}

View file

@ -15,7 +15,8 @@ type Executor struct {
// NewExecutor returns a new instance of Executor.
// The executor always matches the hostname of the first cluster node.
func NewExecutor(holder *pilosa.Holder, cluster *pilosa.Cluster) *Executor {
e := &Executor{Executor: pilosa.NewExecutor(nil)}
executor := pilosa.NewExecutor(nil)
e := &Executor{Executor: executor}
e.Holder = holder
e.Cluster = cluster
e.Scheme = cluster.Nodes[0].Scheme

5
uri.go
View file

@ -144,6 +144,11 @@ func (u URI) Equals(other *URI) bool {
u.port == other.port
}
// Path returns URI with path
func (u *URI) Path(path string) string {
return fmt.Sprintf("%s%s", u.Normalize(), path)
}
// The following methods are required to implement pflag Value interface.
// Set sets the time quantum value.

View file

@ -83,6 +83,17 @@ func TestNormalizedAddress(t *testing.T) {
}
}
func TestURIPath(t *testing.T) {
uri, err := NewURIFromAddress("http+protobuf://big-data.pilosa.com:6888")
if err != nil {
t.Fatal(err)
}
target := "http://big-data.pilosa.com:6888/index/foo"
if uri.Path("/index/foo") != target {
t.Fatalf("%s != %s", uri.Path("/index/foo"), target)
}
}
func TestEquals(t *testing.T) {
uri1 := DefaultURI()
if uri1.Equals(nil) {