variety of cleanup in api and handler

don't export QueryValidationSpecRequired
add docs to some methods
simplify /debug/vars handling using expvar.Handler()
implement Version in API and simplify
This commit is contained in:
Matthew Jaffee 2018-04-11 09:42:05 -05:00
parent dd5b38f4ef
commit 07ca6d57ad
No known key found for this signature in database
GPG key ID: 51C676AF9FFCDB87
2 changed files with 35 additions and 39 deletions

22
api.go
View file

@ -31,6 +31,8 @@ import (
"github.com/pkg/errors"
)
// API provides the top level programmatic interface to Pilosa. It is usually
// wrapped by a handler which provides an external interface (e.g. HTTP).
type API struct {
Holder *Holder
// The execution engine for running queries.
@ -46,6 +48,7 @@ type API struct {
Logger Logger
}
// NewAPI returns a new API instance.
func NewAPI() *API {
return &API{
Broadcaster: NopBroadcaster,
@ -55,7 +58,8 @@ func NewAPI() *API {
}
}
func (a *API) ExecuteQuery(ctx context.Context, req *QueryRequest) (QueryResponse, error) {
// ExecuteQuery parses a PQL query out of the request and executes it.
func (api *API) ExecuteQuery(ctx context.Context, req *QueryRequest) (QueryResponse, error) {
resp := QueryResponse{}
q, err := pql.NewParser(strings.NewReader(req.Query)).Parse()
@ -67,7 +71,7 @@ func (a *API) ExecuteQuery(ctx context.Context, req *QueryRequest) (QueryRespons
ExcludeAttrs: req.ExcludeAttrs,
ExcludeBits: req.ExcludeBits,
}
results, err := a.Executor.Execute(ctx, req.Index, q, req.Slices, execOpts)
results, err := api.Executor.Execute(ctx, req.Index, q, req.Slices, execOpts)
if err != nil {
return resp, err
}
@ -86,7 +90,7 @@ func (a *API) ExecuteQuery(ctx context.Context, req *QueryRequest) (QueryRespons
}
// Retrieve column attributes across all calls.
columnAttrSets, err := a.readColumnAttrSets(a.Holder.Index(req.Index), columnIDs)
columnAttrSets, err := api.readColumnAttrSets(api.Holder.Index(req.Index), columnIDs)
if err != nil {
return resp, err
}
@ -118,6 +122,7 @@ func (api *API) readColumnAttrSets(index *Index, ids []uint64) ([]*ColumnAttrSet
return ax, nil
}
// CreateIndex makes a new Pilosa index.
func (api *API) CreateIndex(ctx context.Context, indexName string, options IndexOptions) (*Index, error) {
// Create index.
index, err := api.Holder.CreateIndex(indexName, options)
@ -845,6 +850,7 @@ func (api *API) inputJSONDataParser(req map[string]interface{}, index *Index, na
return setBits, nil
}
// SetCoordinator makes a new Node the cluster coordinator.
func (api *API) SetCoordinator(ctx context.Context, id string) (oldNode, newNode *Node, err error) {
oldNode = api.Cluster.nodeByID(api.Cluster.Coordinator)
newNode = api.Cluster.nodeByID(id)
@ -869,6 +875,8 @@ func (api *API) SetCoordinator(ctx context.Context, id string) (oldNode, newNode
return oldNode, newNode, nil
}
// RemoveNode puts the cluster into the "RESIZING" state and begins the job of
// removing the given node.
func (api *API) RemoveNode(id string) (*Node, error) {
removeNode := api.Cluster.nodeByID(id)
if removeNode == nil {
@ -891,6 +899,14 @@ func (api *API) ResizeAbort() error {
return errors.Wrap(err, "complete current job")
}
// State returns the cluster state which is usually "NORMAL", but could be
// "STARTING", "RESIZING", or potentially others. See cluster.go for more
// details.
func (api *API) State() string {
return api.Cluster.State()
}
// Version returns the Pilosa version.
func (api *API) Version() string {
return strings.TrimPrefix(Version, "v")
}

View file

@ -108,14 +108,14 @@ func BuildRouters(handler *Handler) {
func (h *Handler) populateValidators() {
h.validators = map[string]*queryValidationSpec{}
h.validators["GetFragmentNodes"] = QueryValidationSpecRequired("slice").Optional("index")
h.validators["GetSliceMax"] = QueryValidationSpecRequired().Optional("inverse")
h.validators["PostQuery"] = QueryValidationSpecRequired().Optional("slices", "columnAttrs", "excludeAttrs", "excludeBits")
h.validators["GetExport"] = QueryValidationSpecRequired("index", "frame", "view", "slice")
h.validators["GetFragmentData"] = QueryValidationSpecRequired("index", "frame", "view", "slice")
h.validators["PostFragmentData"] = QueryValidationSpecRequired("index", "frame", "view", "slice")
h.validators["GetFragmentBlocks"] = QueryValidationSpecRequired("index", "frame", "view", "slice")
h.validators["PostFrameRestore"] = QueryValidationSpecRequired("host")
h.validators["GetFragmentNodes"] = queryValidationSpecRequired("slice").Optional("index")
h.validators["GetSliceMax"] = queryValidationSpecRequired().Optional("inverse")
h.validators["PostQuery"] = queryValidationSpecRequired().Optional("slices", "columnAttrs", "excludeAttrs", "excludeBits")
h.validators["GetExport"] = queryValidationSpecRequired("index", "frame", "view", "slice")
h.validators["GetFragmentData"] = queryValidationSpecRequired("index", "frame", "view", "slice")
h.validators["PostFragmentData"] = queryValidationSpecRequired("index", "frame", "view", "slice")
h.validators["GetFragmentBlocks"] = queryValidationSpecRequired("index", "frame", "view", "slice")
h.validators["PostFrameRestore"] = queryValidationSpecRequired("host")
}
func (h *Handler) queryArgValidator(next http.Handler) http.Handler {
@ -154,7 +154,7 @@ func loadCommon(router *mux.Router, handler *Handler) {
router.HandleFunc("/cluster/message", handler.handlePostClusterMessage).Methods("POST")
router.HandleFunc("/cluster/resize/set-coordinator", handler.handlePostClusterResizeSetCoordinator).Methods("POST")
router.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux).Methods("GET")
router.HandleFunc("/debug/vars", handler.handleExpvar).Methods("GET")
router.Handle("/debug/vars", expvar.Handler()).Methods("GET")
router.HandleFunc("/fragment/data", handler.handleGetFragmentData).Methods("GET").Name("GetFragmentData")
router.HandleFunc("/hosts", handler.handleGetHosts).Methods("GET")
router.HandleFunc("/id", handler.handleGetID).Methods("GET")
@ -174,7 +174,7 @@ func loadRestricted(router *mux.Router, handler *Handler) {
func loadNormal(router *mux.Router, handler *Handler) {
router.HandleFunc("/cluster/resize/remove-node", handler.handlePostClusterResizeRemoveNode).Methods("POST")
router.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux).Methods("GET")
router.HandleFunc("/debug/vars", handler.handleExpvar).Methods("GET")
router.Handle("/debug/vars", expvar.Handler()).Methods("GET")
router.HandleFunc("/export", handler.handleGetExport).Methods("GET").Name("GetExport")
router.HandleFunc("/fragment/block/data", handler.handleGetFragmentBlockData).Methods("GET")
router.HandleFunc("/fragment/blocks", handler.handleGetFragmentBlocks).Methods("GET").Name("GetFragmentBlocks")
@ -270,7 +270,7 @@ func (h *Handler) handleWebUI(w http.ResponseWriter, r *http.Request) {
}
filesystem, err := h.FileSystem.New()
if err != nil {
h.writeQueryResponse(w, r, &QueryResponse{Err: err})
_ = h.writeQueryResponse(w, r, &QueryResponse{Err: err})
h.Logger.Printf("Pilosa WebUI is not available. Please run `make generate-statik` before building Pilosa with `make install`.")
return
}
@ -1337,36 +1337,16 @@ func (h *Handler) handleGetHosts(w http.ResponseWriter, r *http.Request) {
// handleGetVersion handles /version requests.
func (h *Handler) handleGetVersion(w http.ResponseWriter, r *http.Request) {
version := Version
if strings.HasPrefix(version, "v") {
// make the version string semver-compatible
version = version[1:]
}
if err := json.NewEncoder(w).Encode(struct {
err := json.NewEncoder(w).Encode(struct {
Version string `json:"version"`
}{
Version: version,
}); err != nil {
Version: h.API.Version(),
})
if err != nil {
h.Logger.Printf("write version response error: %s", err)
}
}
// handleExpvar handles /debug/vars requests.
func (h *Handler) handleExpvar(w http.ResponseWriter, r *http.Request) {
// Copied from $GOROOT/src/expvar/expvar.go
w.Header().Set("Content-Type", "application/json; charset=utf-8")
fmt.Fprintf(w, "{\n")
first := true
expvar.Do(func(kv expvar.KeyValue) {
if !first {
fmt.Fprintf(w, ",\n")
}
first = false
fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
})
fmt.Fprintf(w, "\n}\n")
}
// QueryResult types.
const (
QueryResultTypeNil uint32 = iota
@ -1809,7 +1789,7 @@ type queryValidationSpec struct {
args map[string]struct{}
}
func QueryValidationSpecRequired(requiredArgs ...string) *queryValidationSpec {
func queryValidationSpecRequired(requiredArgs ...string) *queryValidationSpec {
args := map[string]struct{}{}
for _, arg := range requiredArgs {
args[arg] = struct{}{}