mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 02:44:59 +00:00
Remove MDS and replace it with Controller (#2219)
* Remove MDS and replace it with Controller This commit removes the MDS layer (and package) and shifts Controller package into its place. * add pprof/fgprof to serverless http router --------- Co-authored-by: Matthew Jaffee <jaffee@pilosa.com>
This commit is contained in:
parent
b12c90fdd1
commit
20429bb9dc
67 changed files with 606 additions and 1370 deletions
8
api.go
8
api.go
|
|
@ -3070,9 +3070,9 @@ func (api *API) Directive(ctx context.Context, d *dax.Directive) error {
|
|||
}
|
||||
|
||||
// DirectiveApplied returns true if the computer's current Directive has been
|
||||
// applied and is ready to be queried. This it temporary (primarily for tests)
|
||||
// and needs to be refactored as we improve the logic around mds-to-computer
|
||||
// communication.
|
||||
// applied and is ready to be queried. This is temporary (primarily for tests)
|
||||
// and needs to be refactored as we improve the logic around
|
||||
// controller-to-computer communication.
|
||||
func (api *API) DirectiveApplied(ctx context.Context) (bool, error) {
|
||||
return api.holder.DirectiveApplied(), nil
|
||||
}
|
||||
|
|
@ -3085,7 +3085,7 @@ func (api *API) SnapshotShardData(ctx context.Context, req *dax.SnapshotShardDat
|
|||
}
|
||||
// TODO(jaffee) confirm this node is actually responsible for the given
|
||||
// shard? Not sure we need to given that this request comes from
|
||||
// MDS, but might be a belt&suspenders situation.
|
||||
// the Controller, but might be a belt&suspenders situation.
|
||||
|
||||
qtid := req.TableKey.QualifiedTableID()
|
||||
|
||||
|
|
|
|||
12
ctl/dax.go
12
ctl/dax.go
|
|
@ -14,15 +14,15 @@ func BuildDAXFlags(cmd *cobra.Command, srv *server.Command) {
|
|||
flags.BoolVar(&srv.Config.Verbose, "verbose", srv.Config.Verbose, "Enable verbose logging")
|
||||
flags.StringVar(&srv.Config.LogPath, "log-path", srv.Config.LogPath, "Log path")
|
||||
|
||||
// MDS
|
||||
flags.BoolVar(&srv.Config.MDS.Run, "mds.run", srv.Config.MDS.Run, "Run the MDS service in process.")
|
||||
flags.DurationVar(&srv.Config.MDS.Config.RegistrationBatchTimeout, "mds.config.registration-batch-timeout", srv.Config.MDS.Config.RegistrationBatchTimeout, "Timeout for node registration batches.")
|
||||
flags.StringVar(&srv.Config.MDS.Config.DataDir, "mds.config.data-dir", srv.Config.MDS.Config.DataDir, "MDS directory to use in process.")
|
||||
flags.DurationVar(&srv.Config.MDS.Config.SnappingTurtleTimeout, "mds.config.snapping-turtle-timeout", srv.Config.MDS.Config.SnappingTurtleTimeout, "Period for running automatic snapshotting routine.")
|
||||
// Controller
|
||||
flags.BoolVar(&srv.Config.Controller.Run, "controller.run", srv.Config.Controller.Run, "Run the Controller service in process.")
|
||||
flags.DurationVar(&srv.Config.Controller.Config.RegistrationBatchTimeout, "controller.config.registration-batch-timeout", srv.Config.Controller.Config.RegistrationBatchTimeout, "Timeout for node registration batches.")
|
||||
flags.StringVar(&srv.Config.Controller.Config.DataDir, "controller.config.data-dir", srv.Config.Controller.Config.DataDir, "Controller directory to use in process.")
|
||||
flags.DurationVar(&srv.Config.Controller.Config.SnappingTurtleTimeout, "controller.config.snapping-turtle-timeout", srv.Config.Controller.Config.SnappingTurtleTimeout, "Period for running automatic snapshotting routine.")
|
||||
|
||||
// Queryer
|
||||
flags.BoolVar(&srv.Config.Queryer.Run, "queryer.run", srv.Config.Queryer.Run, "Run the Queryer service in process.")
|
||||
flags.StringVar(&srv.Config.Queryer.Config.MDSAddress, "queryer.config.mds-address", srv.Config.Queryer.Config.MDSAddress, "Address of remote MDS process.")
|
||||
flags.StringVar(&srv.Config.Queryer.Config.ControllerAddress, "queryer.config.controller-address", srv.Config.Queryer.Config.ControllerAddress, "Address of remote Controller process.")
|
||||
|
||||
// Computer
|
||||
flags.BoolVar(&srv.Config.Computer.Run, "computer.run", srv.Config.Computer.Run, "Run the Computer service in process.")
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func serverFlagSet(srv *server.Config, prefix string) *pflag.FlagSet {
|
|||
|
||||
flags := pflag.NewFlagSet("featurebase", pflag.ExitOnError)
|
||||
flags.StringVar(&srv.Name, pre("name"), srv.Name, "Name of the node in the cluster.")
|
||||
flags.StringVar(&srv.MDSAddress, pre("mds-address"), srv.MDSAddress, "MDS service to register with.")
|
||||
flags.StringVar(&srv.ControllerAddress, pre("controller-address"), srv.ControllerAddress, "Controller service to register with.")
|
||||
flags.StringVar(&srv.WriteloggerDir, pre("writelogger-dir"), srv.WriteloggerDir, "Writelogger directory to read/write append logs.")
|
||||
flags.StringVar(&srv.SnapshotterDir, pre("snapshotter-dir"), srv.SnapshotterDir, "Snapshotter directory to read/write snapshots.")
|
||||
flags.StringVarP(&srv.DataDir, pre("data-dir"), short("d"), srv.DataDir, "Directory to store FeatureBase data files.")
|
||||
|
|
@ -112,7 +112,7 @@ func serverFlagSet(srv *server.Config, prefix string) *pflag.FlagSet {
|
|||
|
||||
flags.BoolVar(&srv.SQL.EndpointEnabled, pre("sql.endpoint-enabled"), srv.SQL.EndpointEnabled, "Enable FeatureBase SQL /sql endpoint (default false)")
|
||||
|
||||
flags.DurationVar(&srv.CheckInInterval, pre("check-in-interval"), srv.CheckInInterval, "Interval between check-ins to MDS")
|
||||
flags.DurationVar(&srv.CheckInInterval, pre("check-in-interval"), srv.CheckInInterval, "Interval between check-ins to the Controller")
|
||||
|
||||
// Future flags.
|
||||
flags.BoolVar(&srv.Future.Rename, pre("future.rename"), false, "Present application name as FeatureBase. Defaults to false, will default to true in an upcoming release.")
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ testv:
|
|||
|
||||
test-integration:
|
||||
mkdir -p ../coverage-from-docker
|
||||
$(GO) test ./test/dax -count 1 -run TestDAXIntegration/$(RUN)
|
||||
$(GO) test ./test/dax -count 1 -timeout 20m -run TestDAXIntegration/$(RUN)
|
||||
|
||||
testv-integration:
|
||||
$(GO) test -v ./test/dax -count 1 -run TestDAXIntegration/$(RUN)
|
||||
$(GO) test -v ./test/dax -count 1 -timeout 20m -run TestDAXIntegration/$(RUN)
|
||||
|
||||
|
||||
############################### AWS STUFF ###############################
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
)
|
||||
|
||||
// Registrar represents the methods which Computer uses to register itself with
|
||||
// MDS.
|
||||
// the Controller.
|
||||
type Registrar interface {
|
||||
RegisterNode(ctx context.Context, node *dax.Node) error
|
||||
CheckInNode(ctx context.Context, node *dax.Node) error
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
featurebase "github.com/featurebasedb/featurebase/v3"
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/computer"
|
||||
mdsclient "github.com/featurebasedb/featurebase/v3/dax/mds/client"
|
||||
controllerclient "github.com/featurebasedb/featurebase/v3/dax/controller/client"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/snapshotter"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/writelogger"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
|
|
@ -54,11 +54,11 @@ func (c *computerService) Start() error {
|
|||
c.computer = cmd
|
||||
}
|
||||
|
||||
if c.cfg.ComputerConfig.MDSAddress != "" {
|
||||
mdsAddr := dax.Address(c.cfg.ComputerConfig.MDSAddress)
|
||||
// Set mds (registrar) on computer.
|
||||
if err := c.SetMDS(mdsAddr); err != nil {
|
||||
return errors.Wrapf(err, "setting mds service on computer: %s", c.cfg.Name)
|
||||
if c.cfg.ComputerConfig.ControllerAddress != "" {
|
||||
controllerAddr := dax.Address(c.cfg.ComputerConfig.ControllerAddress)
|
||||
// Set Controller (registrar) on computer.
|
||||
if err := c.SetController(controllerAddr); err != nil {
|
||||
return errors.Wrapf(err, "setting controller service on computer: %s", c.cfg.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -103,8 +103,8 @@ func (c *computerService) HTTPHandler() http.Handler {
|
|||
return c.computer.HTTPHandler()
|
||||
}
|
||||
|
||||
func (c *computerService) SetMDS(addr dax.Address) error {
|
||||
c.computer.Registrar = mdsclient.New(addr, c.logger)
|
||||
func (c *computerService) SetController(addr dax.Address) error {
|
||||
c.computer.Registrar = controllerclient.New(addr, c.logger)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Package balancer is an implementation of the controller's Balancer interface.
|
||||
// Package balancer is an implementation of the controller.Balancer interface.
|
||||
package balancer
|
||||
|
||||
import (
|
||||
|
|
@ -9,8 +9,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/schemar"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/schemar"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
)
|
||||
|
|
@ -18,7 +18,7 @@ import (
|
|||
// Ensure type implements interface.
|
||||
var _ controller.Balancer = (*Balancer)(nil)
|
||||
|
||||
// Balancer is an implementation of the controller.Balancer interface which
|
||||
// Balancer is an implementation of the balancer.Balancer interface which
|
||||
// isolates workers and jobs by database. It helps manage the relationships
|
||||
// between workers and jobs. The logic it uses to balance jobs across workers is
|
||||
// very simple; it bases everything off the number of workers and number of
|
||||
|
|
@ -8,9 +8,9 @@ import (
|
|||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
daxbolt "github.com/featurebasedb/featurebase/v3/dax/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller/balancer/boltdb"
|
||||
schemardb "github.com/featurebasedb/featurebase/v3/dax/mds/schemar/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/balancer/boltdb"
|
||||
schemardb "github.com/featurebasedb/featurebase/v3/dax/controller/schemar/boltdb"
|
||||
daxtest "github.com/featurebasedb/featurebase/v3/dax/test"
|
||||
testbolt "github.com/featurebasedb/featurebase/v3/dax/test/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
|
|
@ -9,9 +9,8 @@ import (
|
|||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller/balancer"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/schemar"
|
||||
balancer "github.com/featurebasedb/featurebase/v3/dax/controller/balancer"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/schemar"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
)
|
||||
|
|
@ -27,7 +26,7 @@ var BalancerBuckets []boltdb.Bucket = []boltdb.Bucket{
|
|||
}
|
||||
|
||||
// NewBalancer returns a new instance of controller.Balancer.
|
||||
func NewBalancer(db *boltdb.DB, schemar schemar.Schemar, logger logger.Logger) controller.Balancer {
|
||||
func NewBalancer(db *boltdb.DB, schemar schemar.Schemar, logger logger.Logger) *balancer.Balancer {
|
||||
fjs := newFreeJobService(db)
|
||||
wjs := newWorkerJobService(db, logger)
|
||||
fws := newFreeWorkerService(db)
|
||||
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
)
|
||||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller/balancer/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/balancer/boltdb"
|
||||
testbolt "github.com/featurebasedb/featurebase/v3/dax/test/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Package client is an HTTP client for MDS.
|
||||
// Package client is an HTTP client for Controller.
|
||||
package client
|
||||
|
||||
import (
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/computer"
|
||||
mdshttp "github.com/featurebasedb/featurebase/v3/dax/mds/http"
|
||||
controllerhttp "github.com/featurebasedb/featurebase/v3/dax/controller/http"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
)
|
||||
|
|
@ -24,8 +24,8 @@ const (
|
|||
var _ computer.Registrar = (*Client)(nil)
|
||||
var _ dax.Schemar = (*Client)(nil)
|
||||
|
||||
// Client is an HTTP client that operates on the MDS endpoints exposed by the
|
||||
// main MDS service.
|
||||
// Client is an HTTP client that operates on the Controller endpoints exposed by
|
||||
// the main Controller service.
|
||||
type Client struct {
|
||||
address dax.Address
|
||||
logger logger.Logger
|
||||
|
|
@ -137,7 +137,7 @@ func (c *Client) DatabaseByID(ctx context.Context, qdbid dax.QualifiedDatabaseID
|
|||
func (c *Client) DatabaseByName(ctx context.Context, orgID dax.OrganizationID, name dax.DatabaseName) (*dax.QualifiedDatabase, error) {
|
||||
url := fmt.Sprintf("%s/database-by-name", c.address.WithScheme(defaultScheme))
|
||||
|
||||
req := &mdshttp.DatabaseByNameRequest{
|
||||
req := &controllerhttp.DatabaseByNameRequest{
|
||||
OrganizationID: orgID,
|
||||
Name: name,
|
||||
}
|
||||
|
|
@ -173,7 +173,7 @@ func (c *Client) DatabaseByName(ctx context.Context, orgID dax.OrganizationID, n
|
|||
func (c *Client) Databases(ctx context.Context, orgID dax.OrganizationID, ids ...dax.DatabaseID) ([]*dax.QualifiedDatabase, error) {
|
||||
url := fmt.Sprintf("%s/databases", c.address.WithScheme(defaultScheme))
|
||||
|
||||
req := &mdshttp.DatabasesRequest{
|
||||
req := &controllerhttp.DatabasesRequest{
|
||||
OrganizationID: orgID,
|
||||
DatabaseIDs: ids,
|
||||
}
|
||||
|
|
@ -291,7 +291,7 @@ func (c *Client) TableID(ctx context.Context, qdbid dax.QualifiedDatabaseID, nam
|
|||
func (c *Client) Tables(ctx context.Context, qdbid dax.QualifiedDatabaseID, ids ...dax.TableID) ([]*dax.QualifiedTable, error) {
|
||||
url := fmt.Sprintf("%s/tables", c.address.WithScheme(defaultScheme))
|
||||
|
||||
req := mdshttp.TablesRequest{
|
||||
req := controllerhttp.TablesRequest{
|
||||
OrganizationID: qdbid.OrganizationID,
|
||||
DatabaseID: qdbid.DatabaseID,
|
||||
TableIDs: ids,
|
||||
|
|
@ -377,7 +377,7 @@ func (c *Client) DropTable(ctx context.Context, qtid dax.QualifiedTableID) error
|
|||
func (c *Client) CreateField(ctx context.Context, qtid dax.QualifiedTableID, fld *dax.Field) error {
|
||||
url := fmt.Sprintf("%s/create-field", c.address.WithScheme(defaultScheme))
|
||||
|
||||
req := mdshttp.CreateFieldRequest{
|
||||
req := controllerhttp.CreateFieldRequest{
|
||||
TableKey: qtid.Key(),
|
||||
Field: fld,
|
||||
}
|
||||
|
|
@ -407,7 +407,7 @@ func (c *Client) DropField(ctx context.Context, qtid dax.QualifiedTableID, fldNa
|
|||
url := fmt.Sprintf("%s/drop-field", c.address.WithScheme(defaultScheme))
|
||||
|
||||
// Encode the request.
|
||||
req := mdshttp.DropFieldRequest{
|
||||
req := controllerhttp.DropFieldRequest{
|
||||
Table: qtid,
|
||||
Field: fldName,
|
||||
}
|
||||
|
|
@ -438,7 +438,7 @@ func (c *Client) IngestShard(ctx context.Context, qtid dax.QualifiedTableID, sha
|
|||
|
||||
var host dax.Address
|
||||
|
||||
req := &mdshttp.IngestShardRequest{
|
||||
req := &controllerhttp.IngestShardRequest{
|
||||
Table: qtid,
|
||||
Shard: shard,
|
||||
}
|
||||
|
|
@ -462,7 +462,7 @@ func (c *Client) IngestShard(ctx context.Context, qtid dax.QualifiedTableID, sha
|
|||
return host, errors.Errorf("status code: %d: %s", resp.StatusCode, b)
|
||||
}
|
||||
|
||||
var isr *mdshttp.IngestShardResponse
|
||||
var isr *controllerhttp.IngestShardResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&isr); err != nil {
|
||||
return host, errors.Wrap(err, "reading response body")
|
||||
}
|
||||
|
|
@ -475,7 +475,7 @@ func (c *Client) IngestPartition(ctx context.Context, qtid dax.QualifiedTableID,
|
|||
|
||||
var host dax.Address
|
||||
|
||||
req := &mdshttp.IngestPartitionRequest{
|
||||
req := &controllerhttp.IngestPartitionRequest{
|
||||
Table: qtid,
|
||||
Partition: partition,
|
||||
}
|
||||
|
|
@ -499,7 +499,7 @@ func (c *Client) IngestPartition(ctx context.Context, qtid dax.QualifiedTableID,
|
|||
return host, errors.Errorf("status code: %d: %s", resp.StatusCode, b)
|
||||
}
|
||||
|
||||
var isr *mdshttp.IngestPartitionResponse
|
||||
var isr *controllerhttp.IngestPartitionResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&isr); err != nil {
|
||||
return host, errors.Wrap(err, "reading response body")
|
||||
}
|
||||
|
|
@ -513,7 +513,7 @@ func (c *Client) ComputeNodes(ctx context.Context, qtid dax.QualifiedTableID, sh
|
|||
|
||||
var nodes []dax.ComputeNode
|
||||
|
||||
req := &mdshttp.ComputeNodesRequest{
|
||||
req := &controllerhttp.ComputeNodesRequest{
|
||||
Table: qtid,
|
||||
Shards: shards,
|
||||
}
|
||||
|
|
@ -537,7 +537,7 @@ func (c *Client) ComputeNodes(ctx context.Context, qtid dax.QualifiedTableID, sh
|
|||
return nodes, errors.Errorf("status code: %d: %s", resp.StatusCode, b)
|
||||
}
|
||||
|
||||
var cnr *mdshttp.ComputeNodesResponse
|
||||
var cnr *controllerhttp.ComputeNodesResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&cnr); err != nil {
|
||||
return nodes, errors.Wrap(err, "reading response body")
|
||||
}
|
||||
|
|
@ -551,7 +551,7 @@ func (c *Client) TranslateNodes(ctx context.Context, qtid dax.QualifiedTableID,
|
|||
|
||||
var nodes []dax.TranslateNode
|
||||
|
||||
req := &mdshttp.TranslateNodesRequest{
|
||||
req := &controllerhttp.TranslateNodesRequest{
|
||||
Table: qtid,
|
||||
Partitions: partitions,
|
||||
}
|
||||
|
|
@ -575,7 +575,7 @@ func (c *Client) TranslateNodes(ctx context.Context, qtid dax.QualifiedTableID,
|
|||
return nodes, errors.Errorf("status code: %d: %s", resp.StatusCode, b)
|
||||
}
|
||||
|
||||
var cnr *mdshttp.TranslateNodesResponse
|
||||
var cnr *controllerhttp.TranslateNodesResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&cnr); err != nil {
|
||||
return nodes, errors.Wrap(err, "reading response body")
|
||||
}
|
||||
|
|
@ -587,7 +587,7 @@ func (c *Client) RegisterNode(ctx context.Context, node *dax.Node) error {
|
|||
url := fmt.Sprintf("%s/register-node", c.address.WithScheme(defaultScheme))
|
||||
c.logger.Debugf("RegisterNode: %s, url: %s", node.Address, url)
|
||||
|
||||
req := &mdshttp.RegisterNodeRequest{
|
||||
req := &controllerhttp.RegisterNodeRequest{
|
||||
Address: node.Address,
|
||||
RoleTypes: node.RoleTypes,
|
||||
}
|
||||
|
|
@ -618,7 +618,7 @@ func (c *Client) CheckInNode(ctx context.Context, node *dax.Node) error {
|
|||
url := fmt.Sprintf("%s/check-in-node", c.address.WithScheme(defaultScheme))
|
||||
c.logger.Debugf("CheckInNode url: %s", url)
|
||||
|
||||
req := &mdshttp.CheckInNodeRequest{
|
||||
req := &controllerhttp.CheckInNodeRequest{
|
||||
Address: node.Address,
|
||||
RoleTypes: node.RoleTypes,
|
||||
}
|
||||
|
|
@ -3,8 +3,6 @@ package controller
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/schemar"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
|
|
@ -12,15 +10,16 @@ type NewBalancerFn func(string, logger.Logger) Balancer
|
|||
|
||||
type Config struct {
|
||||
Director Director
|
||||
Schemar schemar.Schemar
|
||||
|
||||
Balancer Balancer
|
||||
// Poller
|
||||
PollInterval time.Duration `toml:"poll-interval"`
|
||||
|
||||
StorageMethod string
|
||||
BoltDB *boltdb.DB
|
||||
// Storage
|
||||
StorageMethod string `toml:"-"`
|
||||
DataDir string `toml:"-"`
|
||||
|
||||
SnapshotterDir string
|
||||
WriteloggerDir string
|
||||
SnapshotterDir string `toml:"snapshotter-dir"`
|
||||
WriteloggerDir string `toml:"writelogger-dir"`
|
||||
|
||||
// RegistrationBatchTimeout is the time that the controller will
|
||||
// wait after a node registers itself to see if any more nodes
|
||||
|
|
@ -35,5 +34,5 @@ type Config struct {
|
|||
// until the timeout expires to start another round of snapshots.
|
||||
SnappingTurtleTimeout time.Duration
|
||||
|
||||
Logger logger.Logger
|
||||
Logger logger.Logger `toml:"-"`
|
||||
}
|
||||
|
|
@ -10,7 +10,8 @@ import (
|
|||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/computer"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/schemar"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/poller"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/schemar"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/snapshotter"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/writelogger"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
|
|
@ -24,21 +25,26 @@ var _ dax.Schemar = (*Controller)(nil)
|
|||
var _ dax.NodeService = (*Controller)(nil)
|
||||
|
||||
type Controller struct {
|
||||
// Schemar used by the controller to get table information. The controller
|
||||
// should NOT call Schemar methods which modify data. Schema mutations are
|
||||
// made outside of the controller (at this point that happens in MDS).
|
||||
Schemar schemar.Schemar
|
||||
|
||||
boltDB *boltdb.DB
|
||||
// Schemar is used by the controller to get table, and other schema,
|
||||
// information.
|
||||
Schemar schemar.Schemar
|
||||
Balancer Balancer
|
||||
|
||||
// Because we stopped using a storage method interface, and always use bolt,
|
||||
// we need to be sure to close the boltDBs that are created in controller.New()
|
||||
// whenever controller.Stop() is called. These are pointers to that DB so we can
|
||||
// close it.
|
||||
BoltDB *boltdb.DB
|
||||
|
||||
Snapshotter *snapshotter.Snapshotter
|
||||
Writelogger *writelogger.Writelogger
|
||||
|
||||
// Director is used to send directives to computer workers.
|
||||
Director Director
|
||||
|
||||
directiveVersion dax.DirectiveVersion
|
||||
DirectiveVersion dax.DirectiveVersion
|
||||
|
||||
poller *poller.Poller
|
||||
|
||||
registrationBatchTimeout time.Duration
|
||||
nodeChan chan *dax.Node
|
||||
|
|
@ -56,11 +62,16 @@ var supportedRoleTypes []dax.RoleType = []dax.RoleType{
|
|||
|
||||
// New returns a new instance of Controller with default values.
|
||||
func New(cfg Config) *Controller {
|
||||
// Set up logger.
|
||||
var logr logger.Logger = logger.StderrLogger
|
||||
if cfg.Logger != nil {
|
||||
logr = cfg.Logger
|
||||
}
|
||||
|
||||
c := &Controller{
|
||||
Schemar: schemar.NewNopSchemar(),
|
||||
|
||||
boltDB: cfg.BoltDB,
|
||||
Balancer: cfg.Balancer,
|
||||
Balancer: NewNopBalancer(),
|
||||
|
||||
Director: NewNopDirector(),
|
||||
|
||||
|
|
@ -70,38 +81,32 @@ func New(cfg Config) *Controller {
|
|||
snapControl: make(chan struct{}),
|
||||
|
||||
stopping: make(chan struct{}),
|
||||
logger: logger.NopLogger,
|
||||
logger: logr,
|
||||
}
|
||||
|
||||
if cfg.Logger != nil {
|
||||
c.logger = cfg.Logger
|
||||
// Poller.
|
||||
pollerCfg := poller.Config{
|
||||
AddressManager: c,
|
||||
NodeService: c,
|
||||
NodePoller: poller.NewHTTPNodePoller(logr),
|
||||
PollInterval: cfg.PollInterval,
|
||||
Logger: logr,
|
||||
}
|
||||
c.poller = poller.New(pollerCfg)
|
||||
|
||||
// Snapshotter.
|
||||
c.Snapshotter = snapshotter.New(cfg.SnapshotterDir, c.logger)
|
||||
|
||||
// Writelogger.
|
||||
c.Writelogger = writelogger.New(cfg.WriteloggerDir, c.logger)
|
||||
|
||||
switch cfg.StorageMethod {
|
||||
case "boltdb":
|
||||
if err := cfg.BoltDB.InitializeBuckets(boltdb.DirectiveBuckets...); err != nil {
|
||||
c.logger.Panicf("initializing directive buckets: %v", err)
|
||||
}
|
||||
c.directiveVersion = boltdb.NewDirectiveVersion(cfg.BoltDB)
|
||||
default:
|
||||
c.logger.Panicf("storage method '%s' unsupported. (hint: try boltdb)", cfg.StorageMethod)
|
||||
}
|
||||
|
||||
if cfg.Director != nil {
|
||||
c.Director = cfg.Director
|
||||
}
|
||||
if cfg.Schemar != nil {
|
||||
c.Schemar = cfg.Schemar
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Run starts long running subroutines.
|
||||
func (c *Controller) Run() error {
|
||||
// Start starts long running subroutines.
|
||||
func (c *Controller) Start() error {
|
||||
c.poller.Run()
|
||||
|
||||
go c.nodeRegistrationRoutine(c.nodeChan, c.registrationBatchTimeout)
|
||||
go c.snappingTurtleRoutine(c.snappingTurtleTimeout, c.snapControl)
|
||||
|
||||
|
|
@ -109,8 +114,12 @@ func (c *Controller) Run() error {
|
|||
}
|
||||
|
||||
// Stop stops the node registration routine.
|
||||
func (c *Controller) Stop() {
|
||||
func (c *Controller) Stop() error {
|
||||
c.poller.Stop()
|
||||
|
||||
close(c.stopping)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterNodes adds nodes to the controller's list of registered
|
||||
|
|
@ -118,7 +127,7 @@ func (c *Controller) Stop() {
|
|||
func (c *Controller) RegisterNodes(ctx context.Context, nodes ...*dax.Node) error {
|
||||
c.logger.Printf("c.RegisterNodes(): %s", dax.Nodes(nodes))
|
||||
|
||||
tx, err := c.boltDB.BeginTx(ctx, true)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -229,7 +238,7 @@ func (c *Controller) RegisterNode(ctx context.Context, n *dax.Node) error {
|
|||
}
|
||||
}
|
||||
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -251,7 +260,7 @@ func (c *Controller) RegisterNode(ctx context.Context, n *dax.Node) error {
|
|||
// from its list (perhaps due to a network fault) and therefore the node needs
|
||||
// to be re-registered.
|
||||
func (c *Controller) CheckInNode(ctx context.Context, n *dax.Node) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -274,7 +283,7 @@ func (c *Controller) CheckInNode(ctx context.Context, n *dax.Node) error {
|
|||
// DeregisterNodes removes nodes from the controller's list of registered nodes.
|
||||
// It sends directives to the removed nodes, but ignores errors.
|
||||
func (c *Controller) DeregisterNodes(ctx context.Context, addresses ...dax.Address) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, true)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -567,7 +576,7 @@ func (c *Controller) translateWorkersToAssignedNodes(tx dax.Transaction, workers
|
|||
|
||||
// CreateDatabase adds a database to the schemar.
|
||||
func (c *Controller) CreateDatabase(ctx context.Context, qdb *dax.QualifiedDatabase) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, true)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -581,7 +590,7 @@ func (c *Controller) CreateDatabase(ctx context.Context, qdb *dax.QualifiedDatab
|
|||
}
|
||||
|
||||
func (c *Controller) DropDatabase(ctx context.Context, qdbid dax.QualifiedDatabaseID) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, true)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -625,7 +634,7 @@ func (c *Controller) DropDatabase(ctx context.Context, qdbid dax.QualifiedDataba
|
|||
|
||||
// DatabaseByName returns the database for the given name.
|
||||
func (c *Controller) DatabaseByName(ctx context.Context, orgID dax.OrganizationID, dbname dax.DatabaseName) (*dax.QualifiedDatabase, error) {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -641,7 +650,7 @@ func (c *Controller) DatabaseByName(ctx context.Context, orgID dax.OrganizationI
|
|||
|
||||
// DatabaseByID returns the database for the given id.
|
||||
func (c *Controller) DatabaseByID(ctx context.Context, qdbid dax.QualifiedDatabaseID) (*dax.QualifiedDatabase, error) {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -657,7 +666,7 @@ func (c *Controller) DatabaseByID(ctx context.Context, qdbid dax.QualifiedDataba
|
|||
|
||||
// SetDatabaseOptions sets the options on the given database.
|
||||
func (c *Controller) SetDatabaseOptions(ctx context.Context, qdbid dax.QualifiedDatabaseID, opts dax.DatabaseOptions) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, true)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -671,7 +680,7 @@ func (c *Controller) SetDatabaseOptions(ctx context.Context, qdbid dax.Qualified
|
|||
}
|
||||
|
||||
func (c *Controller) Databases(ctx context.Context, orgID dax.OrganizationID, ids ...dax.DatabaseID) ([]*dax.QualifiedDatabase, error) {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -684,7 +693,7 @@ func (c *Controller) Databases(ctx context.Context, orgID dax.OrganizationID, id
|
|||
// CreateTable adds a table to the schemar, and then sends directives to all
|
||||
// affected nodes based on the change.
|
||||
func (c *Controller) CreateTable(ctx context.Context, qtbl *dax.QualifiedTable) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, true)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -772,7 +781,7 @@ func (c *Controller) CreateTable(ctx context.Context, qtbl *dax.QualifiedTable)
|
|||
// DropTable removes a table from the schema and sends directives to all affected
|
||||
// nodes based on the change.
|
||||
func (c *Controller) DropTable(ctx context.Context, qtid dax.QualifiedTableID) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, true)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -840,7 +849,7 @@ func (c *Controller) dropTable(tx dax.Transaction, qtid dax.QualifiedTableID) (A
|
|||
|
||||
// TableByID returns a table by quaified table id.
|
||||
func (c *Controller) TableByID(ctx context.Context, qtid dax.QualifiedTableID) (*dax.QualifiedTable, error) {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -852,7 +861,7 @@ func (c *Controller) TableByID(ctx context.Context, qtid dax.QualifiedTableID) (
|
|||
|
||||
// Tables returns a list of tables by name.
|
||||
func (c *Controller) Tables(ctx context.Context, qdbid dax.QualifiedDatabaseID, ids ...dax.TableID) ([]*dax.QualifiedTable, error) {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -865,7 +874,7 @@ func (c *Controller) Tables(ctx context.Context, qdbid dax.QualifiedDatabaseID,
|
|||
// RemoveShards deregisters the table/shard combinations with the controller and
|
||||
// sends the necessary directives.
|
||||
func (c *Controller) RemoveShards(ctx context.Context, qtid dax.QualifiedTableID, shards ...dax.ShardNum) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, true)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -981,7 +990,7 @@ func (c *Controller) buildDirectives(tx dax.Transaction, addrs []addressMethod)
|
|||
directives := make([]*dax.Directive, len(addrs))
|
||||
|
||||
for i, addressMethod := range addrs {
|
||||
dVersion, err := c.directiveVersion.Increment(tx, 1)
|
||||
dVersion, err := c.DirectiveVersion.Increment(tx, 1)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "incrementing directive version")
|
||||
}
|
||||
|
|
@ -1083,8 +1092,8 @@ func (c *Controller) buildDirectives(tx dax.Transaction, addrs []addressMethod)
|
|||
// the same way we handle shards and partitions, by maintaining a
|
||||
// distinct balancer for FieldVersions. But because the query side isn't
|
||||
// currently set up to look for field translation anywhere but on the
|
||||
// local node (or in the case of MDS, on partition 0), we're keeping
|
||||
// everything that way for now.
|
||||
// local node (or in the case of Serverless, on partition 0), we're
|
||||
// keeping everything that way for now.
|
||||
for tkey := range ownsPartition0 {
|
||||
qtid := tkey.QualifiedTableID()
|
||||
table, err := c.Schemar.Table(tx, qtid)
|
||||
|
|
@ -1154,7 +1163,7 @@ func (c *Controller) SnapshotTable(ctx context.Context, qtid dax.QualifiedTableI
|
|||
// snapshot that shard, then increment its shard version for logs written to the
|
||||
// Writelogger.
|
||||
func (c *Controller) SnapshotShardData(ctx context.Context, qtid dax.QualifiedTableID, shardNum dax.ShardNum) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1197,7 +1206,7 @@ func (c *Controller) snapshotShardData(tx dax.Transaction, qtid dax.QualifiedTab
|
|||
// partition to snapshot the table keys for that partition, then increment its
|
||||
// version for logs written to the Writelogger.
|
||||
func (c *Controller) SnapshotTableKeys(ctx context.Context, qtid dax.QualifiedTableID, partitionNum dax.PartitionNum) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1240,7 +1249,7 @@ func (c *Controller) snapshotTableKeys(tx dax.Transaction, qtid dax.QualifiedTab
|
|||
// to snapshot the keys for that field, then increment its version for logs
|
||||
// written to the Writelogger.
|
||||
func (c *Controller) SnapshotFieldKeys(ctx context.Context, qtid dax.QualifiedTableID, field dax.FieldName) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1294,7 +1303,7 @@ func (c *Controller) ComputeNodes(ctx context.Context, qtid dax.QualifiedTableID
|
|||
}
|
||||
qdbid := qtid.QualifiedDatabaseID
|
||||
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1356,7 +1365,7 @@ func (c *Controller) TranslateNodes(ctx context.Context, qtid dax.QualifiedTable
|
|||
}
|
||||
qdbid := qtid.QualifiedDatabaseID
|
||||
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1431,7 +1440,7 @@ func (c *Controller) IngestPartition(ctx context.Context, qtid dax.QualifiedTabl
|
|||
qdbid := qtid.QualifiedDatabaseID
|
||||
|
||||
// Try with a read transaction first.
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1456,7 +1465,7 @@ func (c *Controller) IngestPartition(ctx context.Context, qtid dax.QualifiedTabl
|
|||
if retryAsWrite {
|
||||
tx.Rollback()
|
||||
|
||||
tx, err = c.boltDB.BeginTx(ctx, true)
|
||||
tx, err = c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1515,7 +1524,7 @@ func (c *Controller) IngestShard(ctx context.Context, qtid dax.QualifiedTableID,
|
|||
qdbid := qtid.QualifiedDatabaseID
|
||||
|
||||
// Try with a read transaction first.
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1540,7 +1549,7 @@ func (c *Controller) IngestShard(ctx context.Context, qtid dax.QualifiedTableID,
|
|||
if retryAsWrite {
|
||||
tx.Rollback()
|
||||
|
||||
tx, err = c.boltDB.BeginTx(ctx, true)
|
||||
tx, err = c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1590,7 +1599,7 @@ func (c *Controller) IngestShard(ctx context.Context, qtid dax.QualifiedTableID,
|
|||
////
|
||||
|
||||
func (c *Controller) CreateField(ctx context.Context, qtid dax.QualifiedTableID, fld *dax.Field) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, true)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1651,7 +1660,7 @@ func (c *Controller) CreateField(ctx context.Context, qtid dax.QualifiedTableID,
|
|||
}
|
||||
|
||||
func (c *Controller) DropField(ctx context.Context, qtid dax.QualifiedTableID, fldName dax.FieldName) error {
|
||||
tx, err := c.boltDB.BeginTx(ctx, true)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1723,7 +1732,7 @@ func (c *Controller) RemoveAddresses(ctx context.Context, addrs ...dax.Address)
|
|||
}
|
||||
|
||||
func (c *Controller) DebugNodes(ctx context.Context) ([]*dax.Node, error) {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1747,7 +1756,7 @@ func (c *Controller) sanitizeQTID(tx dax.Transaction, qtid *dax.QualifiedTableID
|
|||
|
||||
// TableByName gets the full table by name.
|
||||
func (c *Controller) TableByName(ctx context.Context, qdbid dax.QualifiedDatabaseID, name dax.TableName) (*dax.QualifiedTable, error) {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1765,7 +1774,7 @@ func (c *Controller) TableByName(ctx context.Context, qdbid dax.QualifiedDatabas
|
|||
// TableID returns the table id by table name.
|
||||
// TODO(tlt): try to phase this out in favor of TableByName().
|
||||
func (c *Controller) TableID(ctx context.Context, qdbid dax.QualifiedDatabaseID, name dax.TableName) (dax.QualifiedTableID, error) {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return dax.QualifiedTableID{}, errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -1786,7 +1795,7 @@ func (c *Controller) DeleteNode(context.Context, dax.Address) error {
|
|||
return errors.Errorf("Controller.DeleteNode() not implemented")
|
||||
}
|
||||
func (c *Controller) Nodes(ctx context.Context) ([]*dax.Node, error) {
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "beginning tx")
|
||||
}
|
||||
|
|
@ -8,9 +8,10 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller"
|
||||
balancerdb "github.com/featurebasedb/featurebase/v3/dax/mds/controller/balancer/boltdb"
|
||||
schemardb "github.com/featurebasedb/featurebase/v3/dax/mds/schemar/boltdb"
|
||||
directivedb "github.com/featurebasedb/featurebase/v3/dax/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller"
|
||||
balancerdb "github.com/featurebasedb/featurebase/v3/dax/controller/balancer/boltdb"
|
||||
schemardb "github.com/featurebasedb/featurebase/v3/dax/controller/schemar/boltdb"
|
||||
daxtest "github.com/featurebasedb/featurebase/v3/dax/test"
|
||||
testbolt "github.com/featurebasedb/featurebase/v3/dax/test/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
|
|
@ -35,12 +36,11 @@ func TestController(t *testing.T) {
|
|||
testbolt.CleanupDB(t, db.Path())
|
||||
}()
|
||||
|
||||
cfg := controller.Config{
|
||||
Director: director,
|
||||
Schemar: schemar,
|
||||
BoltDB: db,
|
||||
}
|
||||
cfg := controller.Config{}
|
||||
con := controller.New(cfg)
|
||||
con.Schemar = schemar
|
||||
con.BoltDB = db
|
||||
con.Director = director
|
||||
|
||||
// Register a node with an invalid role type.
|
||||
node0 := &dax.Node{
|
||||
|
|
@ -73,19 +73,19 @@ func TestController(t *testing.T) {
|
|||
db := testbolt.MustOpenDB(t)
|
||||
db.InitializeBuckets(balancerdb.BalancerBuckets...)
|
||||
db.InitializeBuckets(schemardb.SchemarBuckets...)
|
||||
db.InitializeBuckets(directivedb.DirectiveBuckets...)
|
||||
defer func() {
|
||||
testbolt.MustCloseDB(t, db)
|
||||
testbolt.CleanupDB(t, db.Path())
|
||||
}()
|
||||
|
||||
cfg := controller.Config{
|
||||
Director: director,
|
||||
Schemar: schemar,
|
||||
BoltDB: db,
|
||||
StorageMethod: "boltdb",
|
||||
Balancer: balancerdb.NewBalancer(db, schemar, logger.StderrLogger),
|
||||
}
|
||||
cfg := controller.Config{}
|
||||
con := controller.New(cfg)
|
||||
con.Schemar = schemar
|
||||
con.Balancer = balancerdb.NewBalancer(db, schemar, logger.StderrLogger)
|
||||
con.DirectiveVersion = directivedb.NewDirectiveVersion(db)
|
||||
con.Director = director
|
||||
con.BoltDB = db
|
||||
|
||||
var exp []*dax.Directive
|
||||
|
||||
|
|
@ -592,19 +592,19 @@ func TestController(t *testing.T) {
|
|||
db := testbolt.MustOpenDB(t)
|
||||
db.InitializeBuckets(balancerdb.BalancerBuckets...)
|
||||
db.InitializeBuckets(schemardb.SchemarBuckets...)
|
||||
db.InitializeBuckets(directivedb.DirectiveBuckets...)
|
||||
defer func() {
|
||||
testbolt.MustCloseDB(t, db)
|
||||
testbolt.CleanupDB(t, db.Path())
|
||||
}()
|
||||
|
||||
cfg := controller.Config{
|
||||
Director: director,
|
||||
Schemar: schemar,
|
||||
BoltDB: db,
|
||||
StorageMethod: "boltdb",
|
||||
Balancer: balancerdb.NewBalancer(db, schemar, logger.StderrLogger),
|
||||
}
|
||||
cfg := controller.Config{}
|
||||
con := controller.New(cfg)
|
||||
con.Schemar = schemar
|
||||
con.Balancer = balancerdb.NewBalancer(db, schemar, logger.StderrLogger)
|
||||
con.DirectiveVersion = directivedb.NewDirectiveVersion(db)
|
||||
con.BoltDB = db
|
||||
con.Director = director
|
||||
|
||||
var exp []*dax.Directive
|
||||
|
||||
|
|
@ -908,18 +908,18 @@ func TestController(t *testing.T) {
|
|||
db := testbolt.MustOpenDB(t)
|
||||
db.InitializeBuckets(balancerdb.BalancerBuckets...)
|
||||
db.InitializeBuckets(schemardb.SchemarBuckets...)
|
||||
db.InitializeBuckets(directivedb.DirectiveBuckets...)
|
||||
defer func() {
|
||||
testbolt.MustCloseDB(t, db)
|
||||
testbolt.CleanupDB(t, db.Path())
|
||||
}()
|
||||
|
||||
cfg := controller.Config{
|
||||
Schemar: schemar,
|
||||
BoltDB: db,
|
||||
StorageMethod: "boltdb",
|
||||
Balancer: balancerdb.NewBalancer(db, schemar, logger.StderrLogger),
|
||||
}
|
||||
cfg := controller.Config{}
|
||||
con := controller.New(cfg)
|
||||
con.Schemar = schemar
|
||||
con.Balancer = balancerdb.NewBalancer(db, schemar, logger.StderrLogger)
|
||||
con.DirectiveVersion = directivedb.NewDirectiveVersion(db)
|
||||
con.BoltDB = db
|
||||
|
||||
// Register two nodes.
|
||||
node0 := &dax.Node{
|
||||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
)
|
||||
|
|
@ -5,19 +5,19 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func Handler(mds *mds.MDS) http.Handler {
|
||||
func Handler(c *controller.Controller) http.Handler {
|
||||
server := &server{
|
||||
mds: mds,
|
||||
controller: c,
|
||||
}
|
||||
|
||||
router := mux.NewRouter()
|
||||
router.HandleFunc("/health", server.getHealth).Methods("GET").Name("GetHealth")
|
||||
|
||||
// mds endpoints.
|
||||
// controller endpoints.
|
||||
router.HandleFunc("/create-database", server.postCreateDatabase).Methods("POST").Name("PostCreateDatabase")
|
||||
router.HandleFunc("/drop-database", server.postDropDatabase).Methods("POST").Name("PostDropDatabase")
|
||||
router.HandleFunc("/database-by-id", server.postDatabaseByID).Methods("POST").Name("PostDatabaseByID")
|
||||
|
|
@ -55,7 +55,7 @@ func Handler(mds *mds.MDS) http.Handler {
|
|||
}
|
||||
|
||||
type server struct {
|
||||
mds *mds.MDS
|
||||
controller *controller.Controller
|
||||
}
|
||||
|
||||
// GET /health
|
||||
|
|
@ -76,7 +76,7 @@ func (s *server) postCreateDatabase(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
err := s.mds.CreateDatabase(ctx, req)
|
||||
err := s.controller.CreateDatabase(ctx, req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -101,7 +101,7 @@ func (s *server) postDropDatabase(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
err := s.mds.DropDatabase(ctx, req)
|
||||
err := s.controller.DropDatabase(ctx, req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -120,7 +120,7 @@ func (s *server) postDatabaseByID(w http.ResponseWriter, r *http.Request) {
|
|||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
resp, err := s.mds.DatabaseByID(ctx, qdbid)
|
||||
resp, err := s.controller.DatabaseByID(ctx, qdbid)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -144,7 +144,7 @@ func (s *server) postDatabaseByName(w http.ResponseWriter, r *http.Request) {
|
|||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
resp, err := s.mds.DatabaseByName(ctx, req.OrganizationID, req.Name)
|
||||
resp, err := s.controller.DatabaseByName(ctx, req.OrganizationID, req.Name)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -176,7 +176,7 @@ func (s *server) postDatabases(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
ids := req.DatabaseIDs
|
||||
|
||||
resp, err := s.mds.Databases(ctx, req.OrganizationID, ids...)
|
||||
resp, err := s.controller.Databases(ctx, req.OrganizationID, ids...)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -207,7 +207,7 @@ func (s *server) postCreateTable(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
err := s.mds.CreateTable(ctx, req)
|
||||
err := s.controller.CreateTable(ctx, req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -231,7 +231,7 @@ func (s *server) postTable(w http.ResponseWriter, r *http.Request) {
|
|||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
resp, err := s.mds.TableByID(ctx, qtid)
|
||||
resp, err := s.controller.TableByID(ctx, qtid)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -256,7 +256,7 @@ func (s *server) postTableID(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
qtbl, err := s.mds.TableByName(ctx, req.QualifiedDatabaseID, req.Name)
|
||||
qtbl, err := s.controller.TableByName(ctx, req.QualifiedDatabaseID, req.Name)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -282,7 +282,7 @@ func (s *server) postDropTable(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
err := s.mds.DropTable(ctx, req)
|
||||
err := s.controller.DropTable(ctx, req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -304,7 +304,7 @@ func (s *server) postCreateField(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
qtid := req.TableKey.QualifiedTableID()
|
||||
|
||||
err := s.mds.CreateField(ctx, qtid, req.Field)
|
||||
err := s.controller.CreateField(ctx, qtid, req.Field)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -331,7 +331,7 @@ func (s *server) postDropField(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
qtid := req.Table
|
||||
|
||||
err := s.mds.DropField(ctx, qtid, req.Field)
|
||||
err := s.controller.DropField(ctx, qtid, req.Field)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -359,7 +359,7 @@ func (s *server) postTables(w http.ResponseWriter, r *http.Request) {
|
|||
qdbid := dax.NewQualifiedDatabaseID(req.OrganizationID, req.DatabaseID)
|
||||
ids := req.TableIDs
|
||||
|
||||
resp, err := s.mds.Tables(ctx, qdbid, ids...)
|
||||
resp, err := s.controller.Tables(ctx, qdbid, ids...)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -393,7 +393,7 @@ func (s *server) postIngestPartition(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
qtid := req.Table
|
||||
|
||||
addr, err := s.mds.IngestPartition(ctx, qtid, req.Partition)
|
||||
addr, err := s.controller.IngestPartition(ctx, qtid, req.Partition)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -433,7 +433,7 @@ func (s *server) postIngestShard(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
qtid := req.Table
|
||||
|
||||
addr, err := s.mds.IngestShard(ctx, qtid, req.Shard)
|
||||
addr, err := s.controller.IngestShard(ctx, qtid, req.Shard)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -472,7 +472,7 @@ func (s *server) postSnapshot(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := s.mds.SnapshotTable(ctx, req); err != nil {
|
||||
if err := s.controller.SnapshotTable(ctx, req); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -494,7 +494,7 @@ func (s *server) postSnapshotShardData(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
qtid := req.Table
|
||||
|
||||
if err := s.mds.SnapshotShardData(ctx, qtid, req.Shard); err != nil {
|
||||
if err := s.controller.SnapshotShardData(ctx, qtid, req.Shard); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -523,7 +523,7 @@ func (s *server) postSnapshotTableKeys(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
qtid := req.Table
|
||||
|
||||
if err := s.mds.SnapshotTableKeys(ctx, qtid, req.Partition); err != nil {
|
||||
if err := s.controller.SnapshotTableKeys(ctx, qtid, req.Partition); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -553,7 +553,7 @@ func (s *server) postSnapshotFieldKeys(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
qtid := req.Table
|
||||
|
||||
if err := s.mds.SnapshotFieldKeys(ctx, qtid, req.Field); err != nil {
|
||||
if err := s.controller.SnapshotFieldKeys(ctx, qtid, req.Field); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -585,7 +585,7 @@ func (s *server) postRegisterNode(w http.ResponseWriter, r *http.Request) {
|
|||
RoleTypes: req.RoleTypes,
|
||||
}
|
||||
|
||||
if err := s.mds.RegisterNode(ctx, node); err != nil {
|
||||
if err := s.controller.RegisterNode(ctx, node); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -615,7 +615,7 @@ func (s *server) postRegisterNodes(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := s.mds.RegisterNodes(ctx, req.Nodes...); err != nil {
|
||||
if err := s.controller.RegisterNodes(ctx, req.Nodes...); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -640,7 +640,7 @@ func (s *server) postDeregisterNodes(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := s.mds.DeregisterNodes(ctx, req.Addresses...); err != nil {
|
||||
if err := s.controller.DeregisterNodes(ctx, req.Addresses...); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -670,7 +670,7 @@ func (s *server) postCheckInNode(w http.ResponseWriter, r *http.Request) {
|
|||
RoleTypes: req.RoleTypes,
|
||||
}
|
||||
|
||||
if err := s.mds.CheckInNode(ctx, node); err != nil {
|
||||
if err := s.controller.CheckInNode(ctx, node); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -702,7 +702,7 @@ func (s *server) postComputeNodes(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
qtid := req.Table
|
||||
|
||||
nodes, err := s.mds.ComputeNodes(ctx, qtid, req.Shards...)
|
||||
nodes, err := s.controller.ComputeNodes(ctx, qtid, req.Shards)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -719,7 +719,7 @@ func (s *server) postComputeNodes(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func (s *server) getDebugNodes(w http.ResponseWriter, r *http.Request) {
|
||||
nodes, err := s.mds.DebugNodes(r.Context())
|
||||
nodes, err := s.controller.DebugNodes(r.Context())
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
|
@ -765,7 +765,7 @@ func (s *server) postTranslateNodes(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
qtid := req.Table
|
||||
|
||||
nodes, err := s.mds.TranslateNodes(ctx, qtid, req.Partitions...)
|
||||
nodes, err := s.controller.TranslateNodes(ctx, qtid, req.Partitions)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller/partitioner"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/partitioner"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
@ -11,8 +11,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
mdshttp "github.com/featurebasedb/featurebase/v3/dax/mds/http"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/poller"
|
||||
controllerhttp "github.com/featurebasedb/featurebase/v3/dax/controller/http"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/poller"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -50,7 +50,7 @@ func TestPoller(t *testing.T) {
|
|||
|
||||
t.Run("Poller", func(t *testing.T) {
|
||||
cfg := poller.Config{
|
||||
AddressManager: mdshttp.NewAddressManager(managerAddr),
|
||||
AddressManager: controllerhttp.NewAddressManager(managerAddr),
|
||||
NodePoller: poller.NewHTTPNodePoller(logger.NopLogger),
|
||||
NodeService: nodeService,
|
||||
}
|
||||
|
|
@ -110,7 +110,7 @@ func newMockManager(t *testing.T, ctx context.Context, deregisterPath string, no
|
|||
body := r.Body
|
||||
defer body.Close()
|
||||
|
||||
req := mdshttp.DeregisterNodesRequest{}
|
||||
req := controllerhttp.DeregisterNodesRequest{}
|
||||
if err := json.NewDecoder(body).Decode(&req); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/schemar"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/schemar"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
)
|
||||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/schemar/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/schemar/boltdb"
|
||||
daxtest "github.com/featurebasedb/featurebase/v3/dax/test"
|
||||
testbolt "github.com/featurebasedb/featurebase/v3/dax/test/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
119
dax/controller/service/controller.go
Normal file
119
dax/controller/service/controller.go
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller"
|
||||
balancerboltdb "github.com/featurebasedb/featurebase/v3/dax/controller/balancer/boltdb"
|
||||
controllerhttp "github.com/featurebasedb/featurebase/v3/dax/controller/http"
|
||||
schemarboltdb "github.com/featurebasedb/featurebase/v3/dax/controller/schemar/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
fbnet "github.com/featurebasedb/featurebase/v3/net"
|
||||
)
|
||||
|
||||
// Ensure type implements interface.
|
||||
var _ dax.Service = (*controllerService)(nil)
|
||||
|
||||
type controllerService struct {
|
||||
uri *fbnet.URI
|
||||
controller *controller.Controller
|
||||
|
||||
// Because we stopped using a storage method interface, and always use bolt,
|
||||
// we need to be sure to close the boltDBs that are created in controller.New()
|
||||
// whenever controller.Stop() is called. These are pointers to that DB so we can
|
||||
// close it.
|
||||
boltDB *boltdb.DB
|
||||
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
func New(uri *fbnet.URI, cfg controller.Config) *controllerService {
|
||||
// Set up logger.
|
||||
var logr logger.Logger = logger.StderrLogger
|
||||
if cfg.Logger != nil {
|
||||
logr = cfg.Logger
|
||||
}
|
||||
|
||||
// Storage methods.
|
||||
if cfg.StorageMethod != "boltdb" && cfg.StorageMethod != "" {
|
||||
logr.Printf("storagemethod %s not supported, try 'boltdb'", cfg.StorageMethod)
|
||||
}
|
||||
|
||||
if cfg.DataDir == "" {
|
||||
dir, err := os.MkdirTemp("", "controller_*")
|
||||
if err != nil {
|
||||
logr.Printf("Making temp dir for Controller storage: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cfg.DataDir = dir
|
||||
logr.Warnf("no DataDir given (like '/path/to/directory'); using temp dir at '%s'", cfg.DataDir)
|
||||
}
|
||||
|
||||
buckets := append(schemarboltdb.SchemarBuckets, balancerboltdb.BalancerBuckets...)
|
||||
|
||||
controllerDB, err := boltdb.NewSvcBolt(cfg.DataDir, "controller", buckets...)
|
||||
if err != nil {
|
||||
logr.Printf(errors.Wrap(err, "creating controller bolt").Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
schemar := schemarboltdb.NewSchemar(controllerDB, logr)
|
||||
balancer := balancerboltdb.NewBalancer(controllerDB, schemar, logr)
|
||||
|
||||
// Directive version.
|
||||
if err := controllerDB.InitializeBuckets(boltdb.DirectiveBuckets...); err != nil {
|
||||
logr.Panicf("initializing directive buckets: %v", err)
|
||||
}
|
||||
directiveVersion := boltdb.NewDirectiveVersion(controllerDB)
|
||||
|
||||
// Controller.
|
||||
controller := controller.New(cfg)
|
||||
controller.Schemar = schemar
|
||||
controller.Balancer = balancer
|
||||
controller.DirectiveVersion = directiveVersion
|
||||
controller.BoltDB = controllerDB
|
||||
|
||||
if cfg.Director != nil {
|
||||
controller.Director = cfg.Director
|
||||
}
|
||||
|
||||
return &controllerService{
|
||||
uri: uri,
|
||||
controller: controller,
|
||||
boltDB: controllerDB,
|
||||
logger: logr,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *controllerService) Start() error {
|
||||
// Start controller service.
|
||||
if err := m.controller.Start(); err != nil {
|
||||
return errors.Wrap(err, "starting controller")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *controllerService) Stop() error {
|
||||
err := m.controller.Stop()
|
||||
if err != nil {
|
||||
m.logger.Warnf("error stopping controller: %v", err)
|
||||
}
|
||||
|
||||
if m.boltDB != nil {
|
||||
m.boltDB.Close()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *controllerService) Address() dax.Address {
|
||||
return dax.Address(m.uri.HostPort() + "/" + dax.ServicePrefixController)
|
||||
}
|
||||
|
||||
func (m *controllerService) HTTPHandler() http.Handler {
|
||||
return controllerhttp.Handler(m.controller)
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ func (c *Controller) snapAll() {
|
|||
c.logger.Debugf("TURTLE: snapAll")
|
||||
ctx := context.Background()
|
||||
|
||||
tx, err := c.boltDB.BeginTx(ctx, false)
|
||||
tx, err := c.BoltDB.BeginTx(ctx, false)
|
||||
if err != nil {
|
||||
c.logger.Printf("Error getting transaction for snapping turtle: %v", err)
|
||||
return
|
||||
|
|
@ -4,7 +4,7 @@ package dax
|
|||
// ServicePrefixes are used as the service prefix value in http handlers.
|
||||
const (
|
||||
ServicePrefixComputer = "computer"
|
||||
ServicePrefixMDS = "mds"
|
||||
ServicePrefixController = "controller"
|
||||
ServicePrefixQueryer = "queryer"
|
||||
ServicePrefixSnapshotter = "snapshotter"
|
||||
ServicePrefixWritelogger = "writelogger"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package dax
|
||||
|
||||
// Directive contains the instructions, sent from MDS, which a compute node is
|
||||
// to follow. A Directive is typically JSON-encoded and POSTed to a compute
|
||||
// node's `/directive` endpoint.
|
||||
// Directive contains the instructions, sent from the Controller, which a
|
||||
// compute node is to follow. A Directive is typically JSON-encoded and POSTed
|
||||
// to a compute node's `/directive` endpoint.
|
||||
type Directive struct {
|
||||
Address Address `json:"address"`
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
version: '3'
|
||||
|
||||
services:
|
||||
mds:
|
||||
controller:
|
||||
build:
|
||||
context: ../.quick
|
||||
dockerfile: ../Dockerfile-dax-quick
|
||||
environment:
|
||||
FEATUREBASE_BIND: 0.0.0.0:8080
|
||||
FEATUREBASE_VERBOSE: "true"
|
||||
FEATUREBASE_MDS_RUN: "true"
|
||||
FEATUREBASE_CONFIG_DATA_DIR: file:/dax-data/mds
|
||||
FEATUREBASE_CONTROLLER_RUN: "true"
|
||||
FEATUREBASE_CONFIG_DATA_DIR: file:/dax-data/controller
|
||||
ports:
|
||||
- "8081:8080"
|
||||
|
||||
|
|
@ -21,9 +21,9 @@ services:
|
|||
FEATUREBASE_BIND: 0.0.0.0:8080
|
||||
FEATUREBASE_VERBOSE: "true"
|
||||
FEATUREBASE_QUERYER_RUN: "true"
|
||||
FEATUREBASE_QUERYER_CONFIG_MDS_ADDRESS: "mds:8080/mds"
|
||||
FEATUREBASE_QUERYER_CONFIG_CONTROLLER_ADDRESS: "controller:8080/controller"
|
||||
depends_on:
|
||||
- mds
|
||||
- controller
|
||||
ports:
|
||||
- "8080:8080"
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ services:
|
|||
dockerfile: ../Dockerfile-dax-quick
|
||||
environment:
|
||||
FEATUREBASE_COMPUTER_RUN: "true"
|
||||
FEATUREBASE_COMPUTER_CONFIG_MDS_ADDRESS: "mds:8080/mds"
|
||||
FEATUREBASE_COMPUTER_CONFIG_CONTROLLER_ADDRESS: "controller:8080/controller"
|
||||
FEATUREBASE_COMPUTER_CONFIG_DATA_DIR: /dax-data/computer
|
||||
FEATUREBASE_COMPUTER_CONFIG_VERBOSE: true
|
||||
FEATUREBASE_BIND: 0.0.0.0:8080
|
||||
|
|
@ -45,7 +45,7 @@ services:
|
|||
- "./dax-data/writelogger:/dax-data/writelogger"
|
||||
- "./dax-data/snapshotter:/dax-data/snapshotter"
|
||||
depends_on:
|
||||
- mds
|
||||
- controller
|
||||
deploy:
|
||||
replicas: 1
|
||||
|
||||
|
|
@ -60,5 +60,5 @@ services:
|
|||
GEN_FEATUREBASE_DB_ID: "testdb"
|
||||
GEN_USE_SHARD_TRANSACTIONAL_ENDPOINT: "true"
|
||||
GEN_SOURCE: "custom"
|
||||
GEN_TARGET: "mds"
|
||||
GEN_MDS_ADDRESS: "mds:8080/mds"
|
||||
GEN_TARGET: "serverless"
|
||||
GEN_CONTROLLER_ADDRESS: "controller:8080/controller"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/queryer"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/snapshotter"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/writelogger"
|
||||
|
|
@ -29,7 +29,7 @@ type Handler struct {
|
|||
|
||||
server *http.Server
|
||||
|
||||
mds *mds.MDS
|
||||
controller *controller.Controller
|
||||
writeLogger *writelogger.Writelogger
|
||||
snapshotter *snapshotter.Snapshotter
|
||||
queryer *queryer.Queryer
|
||||
|
|
@ -49,9 +49,9 @@ func OptHandlerBind(b string) HandlerOption {
|
|||
}
|
||||
}
|
||||
|
||||
func OptHandlerMDS(m *mds.MDS) HandlerOption {
|
||||
func OptHandlerController(c *controller.Controller) HandlerOption {
|
||||
return func(h *Handler) error {
|
||||
h.mds = m
|
||||
h.controller = c
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,548 +0,0 @@
|
|||
openapi: 3.0.3
|
||||
|
||||
info:
|
||||
title: MDS
|
||||
description: Metadata Services.
|
||||
version: 0.0.0
|
||||
|
||||
paths:
|
||||
/mds/health:
|
||||
get:
|
||||
summary: Health check endpoint.
|
||||
description: Provides an endpoint to check the overall health of the MDS service.
|
||||
operationId: GetHealth
|
||||
responses:
|
||||
200:
|
||||
description: Service is healthy.
|
||||
|
||||
/mds/create-table:
|
||||
post:
|
||||
summary: Create a table.
|
||||
description: Create a table based on the provided schema.
|
||||
operationId: PostCreateTable
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
examples:
|
||||
table:
|
||||
$ref: '#/components/examples/Table'
|
||||
schema:
|
||||
$ref: '#/components/schemas/Table'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/CreateTableResponse'
|
||||
|
||||
/mds/drop-table:
|
||||
post:
|
||||
summary: Drop a table.
|
||||
description: Drop a table based on the provided table name.
|
||||
operationId: PostDropTable
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
name: tbl
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: Table was dropped.
|
||||
|
||||
/mds/create-field:
|
||||
post:
|
||||
summary: Create a field.
|
||||
description: Create a field based on the provided table and schema.
|
||||
operationId: PostCreateField
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
table: tbl
|
||||
field:
|
||||
name: a_string
|
||||
type: string
|
||||
options:
|
||||
cacheType: ranked
|
||||
cacheSize: 50000
|
||||
schema:
|
||||
$ref: '#/components/schemas/TableField'
|
||||
responses:
|
||||
200:
|
||||
description: Field was created.
|
||||
|
||||
/mds/drop-field:
|
||||
post:
|
||||
summary: Drop a field.
|
||||
description: Drop a field based on the provided table and field name.
|
||||
operationId: PostDropField
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
table: tbl
|
||||
field: fld
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
table:
|
||||
type: string
|
||||
field:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: Field was dropped.
|
||||
|
||||
/mds/table:
|
||||
post:
|
||||
summary: Get a table.
|
||||
description: Get a table based on the provided table name.
|
||||
operationId: PostTable
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
name: tbl
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Table'
|
||||
|
||||
/mds/tables:
|
||||
post:
|
||||
summary: Get a list of table.
|
||||
description: Get a list of tables. If a filter is provided, only those tables will be included in the result.
|
||||
operationId: PostTables
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
names:
|
||||
- tbl1
|
||||
- tbl2
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
names:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Tables'
|
||||
|
||||
/mds/ingest-partition:
|
||||
post:
|
||||
summary: Request to ingest partition data.
|
||||
description: Request to ingest (write) partition data. The address of the compute node responsible is returned.
|
||||
operationId: PostIngestPartition
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
table: tbl
|
||||
partition: 7
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
table:
|
||||
type: string
|
||||
partition:
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Address'
|
||||
|
||||
/mds/ingest-shard:
|
||||
post:
|
||||
summary: Request to ingest shard data.
|
||||
description: Request to ingest (write) shard data. The address of the compute node responsible is returned.
|
||||
operationId: PostIngestShard
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
table: tbl
|
||||
shard: 12
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
table:
|
||||
type: string
|
||||
shard:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Address'
|
||||
|
||||
/mds/snapshot/shard-data:
|
||||
post:
|
||||
summary: Request to snapshot shard data.
|
||||
description: Request to snapshot shard data.
|
||||
operationId: PostSnapshotShardData
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
table: tbl
|
||||
shard: 12
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
table:
|
||||
type: string
|
||||
shard:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
200:
|
||||
description: Shard snapshot was successful.
|
||||
|
||||
/mds/snapshot/table-keys:
|
||||
post:
|
||||
summary: Request to snapshot table keys.
|
||||
description: Request to snapshot table keys.
|
||||
operationId: PostSnapshotTableKeys
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
table: tbl
|
||||
partition: 7
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
table:
|
||||
type: string
|
||||
partition:
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
200:
|
||||
description: Table keys snapshot was successful.
|
||||
|
||||
/mds/snapshot/field-keys:
|
||||
post:
|
||||
summary: Request to snapshot field keys.
|
||||
description: Request to snapshot field keys.
|
||||
operationId: PostSnapshotFieldKeys
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
table: tbl
|
||||
field: fld
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
table:
|
||||
type: string
|
||||
field:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: Field keys snapshot was successful.
|
||||
|
||||
/mds/register-node:
|
||||
post:
|
||||
summary: Register node.
|
||||
description: Register a node with MDS.
|
||||
operationId: PostRegisterNode
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
address: 10.0.0.1:8000
|
||||
roleTypes:
|
||||
- compute
|
||||
- translate
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
address:
|
||||
type: string
|
||||
roleTypes:
|
||||
type: array
|
||||
items:
|
||||
types: string
|
||||
responses:
|
||||
200:
|
||||
description: Node registration was successful.
|
||||
|
||||
/mds/deregister-nodes:
|
||||
post:
|
||||
summary: Deregister nodes.
|
||||
description: Deregister nodes with MDS.
|
||||
operationId: PostDeregisterNodes
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
address: 10.0.0.1:8000
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
address:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: Node deregistration was successful.
|
||||
|
||||
/mds/compute-nodes:
|
||||
post:
|
||||
summary: Get compute nodes.
|
||||
description: Get the compute nodes responsible for the given shards.
|
||||
operationId: PostComputeNodes
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
table: tbl
|
||||
shards:
|
||||
- 10
|
||||
- 11
|
||||
- 12
|
||||
isWrite: false
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
table:
|
||||
type: string
|
||||
shards:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
format: int64
|
||||
isWrite:
|
||||
type: boolean
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/ComputeNodes'
|
||||
|
||||
/mds/translate-nodes:
|
||||
post:
|
||||
summary: Get translate nodes.
|
||||
description: Get the translate nodes responsible for the given partitions.
|
||||
operationId: PostTranslateNodes
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
table: tbl
|
||||
partitions:
|
||||
- 6
|
||||
- 7
|
||||
isWrite: false
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
table:
|
||||
type: string
|
||||
partitions:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
format: int32
|
||||
isWrite:
|
||||
type: boolean
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/TranslateNodes'
|
||||
|
||||
components:
|
||||
responses:
|
||||
CreateTableResponse:
|
||||
description: Placeholder response.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
|
||||
Address:
|
||||
description: Single node address.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
address:
|
||||
type: string
|
||||
|
||||
Table:
|
||||
description: Table response.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Table'
|
||||
|
||||
Tables:
|
||||
description: Tables response.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Table'
|
||||
|
||||
ComputeNodes:
|
||||
description: Compute nodes response.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ComputeNode'
|
||||
|
||||
TranslateNodes:
|
||||
description: Translate nodes response.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/TranslateNode'
|
||||
|
||||
schemas:
|
||||
ComputeNode:
|
||||
type: object
|
||||
properties:
|
||||
address:
|
||||
type: string
|
||||
table:
|
||||
type: string
|
||||
shards:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
TranslateNode:
|
||||
type: object
|
||||
properties:
|
||||
address:
|
||||
type: string
|
||||
table:
|
||||
type: string
|
||||
partitions:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
format: int32
|
||||
|
||||
Table:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
fields:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Field'
|
||||
partitionN:
|
||||
type: integer
|
||||
format: int32
|
||||
|
||||
TableField:
|
||||
type: object
|
||||
properties:
|
||||
table:
|
||||
type: string
|
||||
field:
|
||||
$ref: '#/components/schemas/Field'
|
||||
|
||||
Field:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- bool
|
||||
- decimal
|
||||
- id
|
||||
- idset
|
||||
- int
|
||||
- string
|
||||
- stringset
|
||||
- timestamp
|
||||
options:
|
||||
type: object
|
||||
properties:
|
||||
min:
|
||||
type: integer
|
||||
format: int64
|
||||
max:
|
||||
type: integer
|
||||
format: int64
|
||||
scale:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
noStandardView:
|
||||
type: boolean
|
||||
cacheType:
|
||||
type: string
|
||||
cacheSize:
|
||||
type: integer
|
||||
format: int32
|
||||
timeUnit:
|
||||
type: string
|
||||
epoch:
|
||||
type: string
|
||||
format: date-time
|
||||
timeQuantum:
|
||||
type: string
|
||||
ttl:
|
||||
type: string
|
||||
foreignIndex:
|
||||
type: string
|
||||
|
||||
examples:
|
||||
Table:
|
||||
name: tbl
|
||||
fields:
|
||||
- name: _id
|
||||
type: string
|
||||
- name: a_bool
|
||||
type: bool
|
||||
- name: an_id
|
||||
type: id
|
||||
options:
|
||||
cacheType: ranked
|
||||
cacheSize: 50000
|
||||
- name: an_id_set
|
||||
type: idset
|
||||
options:
|
||||
cacheType: ranked
|
||||
cacheSize: 50000
|
||||
- name: a_string
|
||||
type: string
|
||||
options:
|
||||
cacheType: ranked
|
||||
cacheSize: 50000
|
||||
- name: a_string_set
|
||||
type: stringset
|
||||
options:
|
||||
cacheType: ranked
|
||||
cacheSize: 50000
|
||||
- name: an_int
|
||||
type: int
|
||||
options:
|
||||
min: -100
|
||||
max: 500
|
||||
- name: a_decimal
|
||||
type: decimal
|
||||
options:
|
||||
min: -10.24
|
||||
max: 50.75
|
||||
scale: 2
|
||||
partitionN: 16
|
||||
300
dax/mds/mds.go
300
dax/mds/mds.go
|
|
@ -1,300 +0,0 @@
|
|||
// Package mds provides the overall interface to Metadata Services.
|
||||
package mds
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/computer"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller"
|
||||
balancerboltdb "github.com/featurebasedb/featurebase/v3/dax/mds/controller/balancer/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/poller"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/schemar"
|
||||
schemarboltdb "github.com/featurebasedb/featurebase/v3/dax/mds/schemar/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
// TODO(jaffee) director on config is a bit weird? Shouldn't this be set up internally?
|
||||
Director controller.Director `toml:"-"`
|
||||
// RegistrationBatchTimeout is the time that the controller will
|
||||
// wait after a node registers itself to see if any more nodes
|
||||
// will register before sending out directives to all nodes which
|
||||
// have been registered.
|
||||
RegistrationBatchTimeout time.Duration `toml:"registration-batch-timeout"`
|
||||
|
||||
SnappingTurtleTimeout time.Duration
|
||||
|
||||
// Poller
|
||||
PollInterval time.Duration `toml:"poll-interval"`
|
||||
|
||||
// Storage
|
||||
StorageMethod string `toml:"-"`
|
||||
DataDir string `toml:"-"`
|
||||
|
||||
SnapshotterDir string `toml:"snapshotter-dir"`
|
||||
WriteloggerDir string `toml:"writelogger-dir"`
|
||||
|
||||
// Logger
|
||||
Logger logger.Logger `toml:"-"`
|
||||
}
|
||||
|
||||
// Ensure type implements interface.
|
||||
var _ computer.Registrar = (*MDS)(nil)
|
||||
var _ dax.Schemar = (*MDS)(nil)
|
||||
|
||||
// MDS provides public MDS methods for an MDS service.
|
||||
type MDS struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
controller *controller.Controller
|
||||
poller *poller.Poller
|
||||
schemar schemar.Schemar
|
||||
|
||||
// Because we stopped using a storage method interface, and always use bolt,
|
||||
// we need to be sure to close the boltDBs that are created in mds.New()
|
||||
// whenever mds.Close() is called. These are pointers to those DBs so we can
|
||||
// close them.
|
||||
controllerDB *boltdb.DB
|
||||
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
// New returns a new instance of MDS.
|
||||
func New(cfg Config) *MDS {
|
||||
// Set up logger.
|
||||
var logr logger.Logger = logger.StderrLogger
|
||||
if cfg.Logger != nil {
|
||||
logr = cfg.Logger
|
||||
}
|
||||
|
||||
// Storage methods.
|
||||
if cfg.StorageMethod != "boltdb" && cfg.StorageMethod != "" {
|
||||
logr.Printf("storagemethod %s not supported, try 'boltdb'", cfg.StorageMethod)
|
||||
}
|
||||
|
||||
cfg.StorageMethod = "boltdb"
|
||||
|
||||
if cfg.DataDir == "" {
|
||||
dir, err := os.MkdirTemp("", "mds_*")
|
||||
if err != nil {
|
||||
logr.Printf("Making temp dir for MDS storage: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cfg.DataDir = dir
|
||||
logr.Warnf("no DataDir given (like '/path/to/directory') using temp dir at '%s'", cfg.DataDir)
|
||||
}
|
||||
|
||||
buckets := append(schemarboltdb.SchemarBuckets, balancerboltdb.BalancerBuckets...)
|
||||
controllerDB, err := boltdb.NewSvcBolt(cfg.DataDir, "controller", buckets...)
|
||||
if err != nil {
|
||||
logr.Printf(errors.Wrap(err, "creating controller bolt").Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
schemar := schemarboltdb.NewSchemar(controllerDB, logr)
|
||||
|
||||
controllerCfg := controller.Config{
|
||||
Director: cfg.Director,
|
||||
Schemar: schemar,
|
||||
|
||||
Balancer: balancerboltdb.NewBalancer(controllerDB, schemar, logr),
|
||||
|
||||
RegistrationBatchTimeout: cfg.RegistrationBatchTimeout,
|
||||
SnappingTurtleTimeout: cfg.SnappingTurtleTimeout,
|
||||
SnapshotterDir: cfg.SnapshotterDir,
|
||||
WriteloggerDir: cfg.WriteloggerDir,
|
||||
|
||||
StorageMethod: cfg.StorageMethod,
|
||||
// just reusing this bolt for internal controller svcs
|
||||
// rn... ultimately controller shouldn't know what bolt is at
|
||||
// all
|
||||
BoltDB: controllerDB,
|
||||
|
||||
Logger: logr,
|
||||
}
|
||||
controller := controller.New(controllerCfg)
|
||||
|
||||
pollerCfg := poller.Config{
|
||||
AddressManager: controller,
|
||||
NodeService: controller,
|
||||
NodePoller: poller.NewHTTPNodePoller(logr),
|
||||
PollInterval: cfg.PollInterval,
|
||||
Logger: logr,
|
||||
}
|
||||
poller := poller.New(pollerCfg)
|
||||
|
||||
return &MDS{
|
||||
controller: controller,
|
||||
poller: poller,
|
||||
schemar: schemar,
|
||||
|
||||
controllerDB: controllerDB,
|
||||
|
||||
logger: logr,
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// mds specific endpoints
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
// Start starts MDS services, such as the Poller.
|
||||
func (m *MDS) Start() error {
|
||||
m.poller.Run()
|
||||
return m.controller.Run()
|
||||
}
|
||||
|
||||
// Stop stops MDS services, such as the Poller and the controller's node
|
||||
// registration routine.
|
||||
func (m *MDS) Stop() error {
|
||||
m.poller.Stop()
|
||||
m.controller.Stop()
|
||||
|
||||
if m.controllerDB != nil {
|
||||
m.controllerDB.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateDatabase handles a create table request.
|
||||
func (m *MDS) CreateDatabase(ctx context.Context, qdb *dax.QualifiedDatabase) error {
|
||||
return m.controller.CreateDatabase(ctx, qdb)
|
||||
}
|
||||
|
||||
func (m *MDS) DropDatabase(ctx context.Context, qdbid dax.QualifiedDatabaseID) error {
|
||||
return m.controller.DropDatabase(ctx, qdbid)
|
||||
}
|
||||
|
||||
func (m *MDS) DatabaseByName(ctx context.Context, orgID dax.OrganizationID, dbname dax.DatabaseName) (*dax.QualifiedDatabase, error) {
|
||||
return m.controller.DatabaseByName(ctx, orgID, dbname)
|
||||
}
|
||||
|
||||
func (m *MDS) DatabaseByID(ctx context.Context, qdbid dax.QualifiedDatabaseID) (*dax.QualifiedDatabase, error) {
|
||||
return m.controller.DatabaseByID(ctx, qdbid)
|
||||
}
|
||||
|
||||
func (m *MDS) Databases(ctx context.Context, orgID dax.OrganizationID, ids ...dax.DatabaseID) ([]*dax.QualifiedDatabase, error) {
|
||||
return m.controller.Databases(ctx, orgID, ids...)
|
||||
}
|
||||
|
||||
// CreateTable handles a create table request.
|
||||
func (m *MDS) CreateTable(ctx context.Context, qtbl *dax.QualifiedTable) error {
|
||||
return m.controller.CreateTable(ctx, qtbl)
|
||||
}
|
||||
|
||||
// DropTable handles a drop table request. // TODO(jaffee) how do we
|
||||
// reason about consistency here? What if controller DropTable
|
||||
// succeeds, but schemar fails?
|
||||
func (m *MDS) DropTable(ctx context.Context, qtid dax.QualifiedTableID) error {
|
||||
return m.controller.DropTable(ctx, qtid)
|
||||
}
|
||||
|
||||
// CreateField handles a create Field request.
|
||||
func (m *MDS) CreateField(ctx context.Context, qtid dax.QualifiedTableID, fld *dax.Field) error {
|
||||
return m.controller.CreateField(ctx, qtid, fld)
|
||||
}
|
||||
|
||||
// DropField handles a drop Field request.
|
||||
func (m *MDS) DropField(ctx context.Context, qtid dax.QualifiedTableID, fldName dax.FieldName) error {
|
||||
return m.controller.DropField(ctx, qtid, fldName)
|
||||
}
|
||||
|
||||
// TableByID handles a table request.
|
||||
func (m *MDS) TableByID(ctx context.Context, qtid dax.QualifiedTableID) (*dax.QualifiedTable, error) {
|
||||
return m.controller.TableByID(ctx, qtid)
|
||||
}
|
||||
|
||||
// Tables handles a tables request.
|
||||
func (m *MDS) Tables(ctx context.Context, qdbid dax.QualifiedDatabaseID, ids ...dax.TableID) ([]*dax.QualifiedTable, error) {
|
||||
return m.controller.Tables(ctx, qdbid, ids...)
|
||||
}
|
||||
|
||||
// TableByName handles a table id (i.e. by name) request.
|
||||
func (m *MDS) TableByName(ctx context.Context, qdbid dax.QualifiedDatabaseID, name dax.TableName) (*dax.QualifiedTable, error) {
|
||||
return m.controller.TableByName(ctx, qdbid, name)
|
||||
}
|
||||
|
||||
// IngestPartition handles an ingest partition request.
|
||||
func (m *MDS) IngestPartition(ctx context.Context, qtid dax.QualifiedTableID, partnNum dax.PartitionNum) (dax.Address, error) {
|
||||
return m.controller.IngestPartition(ctx, qtid, partnNum)
|
||||
}
|
||||
|
||||
// IngestShard handles an ingest shard request.
|
||||
func (m *MDS) IngestShard(ctx context.Context, qtid dax.QualifiedTableID, shrdNum dax.ShardNum) (dax.Address, error) {
|
||||
return m.controller.IngestShard(ctx, qtid, shrdNum)
|
||||
}
|
||||
|
||||
// SnapshotTable handles a snapshot table request.
|
||||
func (m *MDS) SnapshotTable(ctx context.Context, qtid dax.QualifiedTableID) error {
|
||||
return m.controller.SnapshotTable(ctx, qtid)
|
||||
}
|
||||
|
||||
// SnapshotShardData handles a snapshot shard request.
|
||||
func (m *MDS) SnapshotShardData(ctx context.Context, qtid dax.QualifiedTableID, shardNum dax.ShardNum) error {
|
||||
return m.controller.SnapshotShardData(ctx, qtid, shardNum)
|
||||
}
|
||||
|
||||
// SnapshotTableKeys handles a snapshot table/keys request.
|
||||
func (m *MDS) SnapshotTableKeys(ctx context.Context, qtid dax.QualifiedTableID, partitionNum dax.PartitionNum) error {
|
||||
return m.controller.SnapshotTableKeys(ctx, qtid, partitionNum)
|
||||
}
|
||||
|
||||
// SnapshotFieldKeys handles a snapshot field/keys request.
|
||||
func (m *MDS) SnapshotFieldKeys(ctx context.Context, qtid dax.QualifiedTableID, fldName dax.FieldName) error {
|
||||
return m.controller.SnapshotFieldKeys(ctx, qtid, fldName)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// controller specific endpoints
|
||||
// These are just pass-throughs for now.
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
// RegisterNode handles a node registration request. It does not
|
||||
// synchronously do much of anything, but the node will eventually
|
||||
// probably get a directive... unless the MDS crashes or something in
|
||||
// which case the fact that this endpoint was ever called will be lost
|
||||
// to time.
|
||||
func (m *MDS) RegisterNode(ctx context.Context, node *dax.Node) error {
|
||||
return m.controller.RegisterNode(ctx, node)
|
||||
}
|
||||
|
||||
// CheckInNode handles a node check-in request. If MDS is not aware of the node,
|
||||
// it will be sent through the RegisterNode process.
|
||||
func (m *MDS) CheckInNode(ctx context.Context, node *dax.Node) error {
|
||||
return m.controller.CheckInNode(ctx, node)
|
||||
}
|
||||
|
||||
// RegisterNodes immediately registers the given nodes and sends out
|
||||
// new directives synchronously, bypassing the wait time of the
|
||||
// RegisterNode endpoint.
|
||||
func (m *MDS) RegisterNodes(ctx context.Context, nodes ...*dax.Node) error {
|
||||
return m.controller.RegisterNodes(ctx, nodes...)
|
||||
}
|
||||
|
||||
// DeregisterNodes handles a request to deregister multiple nodes at once.
|
||||
func (m *MDS) DeregisterNodes(ctx context.Context, addrs ...dax.Address) error {
|
||||
return m.controller.DeregisterNodes(ctx, addrs...)
|
||||
}
|
||||
|
||||
// ComputeNodes gets the compute nodes responsible for the table/shards
|
||||
// specified in the ComputeNodeRequest.
|
||||
func (m *MDS) ComputeNodes(ctx context.Context, qtid dax.QualifiedTableID, shardNums ...dax.ShardNum) ([]dax.ComputeNode, error) {
|
||||
return m.controller.ComputeNodes(ctx, qtid, shardNums)
|
||||
}
|
||||
|
||||
func (m *MDS) DebugNodes(ctx context.Context) ([]*dax.Node, error) {
|
||||
return m.controller.DebugNodes(ctx)
|
||||
}
|
||||
|
||||
// TranslateNodes gets the translate nodes responsible for the table/partitions
|
||||
// specified in the TranslateNodeRequest.
|
||||
func (m *MDS) TranslateNodes(ctx context.Context, qtid dax.QualifiedTableID, partitionNums ...dax.PartitionNum) ([]dax.TranslateNode, error) {
|
||||
return m.controller.TranslateNodes(ctx, qtid, partitionNums)
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds"
|
||||
mdshttp "github.com/featurebasedb/featurebase/v3/dax/mds/http"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
fbnet "github.com/featurebasedb/featurebase/v3/net"
|
||||
)
|
||||
|
||||
// Ensure type implements interface.
|
||||
var _ dax.Service = (*mdsService)(nil)
|
||||
|
||||
type mdsService struct {
|
||||
uri *fbnet.URI
|
||||
mds *mds.MDS
|
||||
}
|
||||
|
||||
func New(uri *fbnet.URI, mds *mds.MDS) *mdsService {
|
||||
return &mdsService{
|
||||
uri: uri,
|
||||
mds: mds,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mdsService) Start() error {
|
||||
// Start mds service.
|
||||
if err := m.mds.Start(); err != nil {
|
||||
return errors.Wrap(err, "starting mds")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mdsService) Stop() error {
|
||||
return m.mds.Stop()
|
||||
}
|
||||
|
||||
func (m *mdsService) Address() dax.Address {
|
||||
return dax.Address(m.uri.HostPort() + "/" + dax.ServicePrefixMDS)
|
||||
}
|
||||
|
||||
func (m *mdsService) HTTPHandler() http.Handler {
|
||||
return mdshttp.Handler(m.mds)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Package client is an HTTP client for MDS.
|
||||
// Package client is an HTTP client for the Queryer.
|
||||
package client
|
||||
|
||||
import (
|
||||
|
|
@ -20,8 +20,8 @@ const (
|
|||
defaultScheme = "http"
|
||||
)
|
||||
|
||||
// Client is an HTTP client that operates on the MDS endpoints exposed by the
|
||||
// main MDS service.
|
||||
// Client is an HTTP client that operates on the Controller endpoints exposed by
|
||||
// the main Controller service.
|
||||
type Client struct {
|
||||
address dax.Address
|
||||
logger logger.Logger
|
||||
|
|
|
|||
|
|
@ -12,6 +12,6 @@ import (
|
|||
// We initially did that with something called "Injections", but that separation
|
||||
// was a bit premature.
|
||||
type Config struct {
|
||||
MDSAddress string `toml:"mds-address"`
|
||||
Logger logger.Logger `toml:"-"`
|
||||
ControllerAddress string `toml:"controller-address"`
|
||||
Logger logger.Logger `toml:"-"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,17 +44,17 @@ type Topologer interface {
|
|||
ComputeNodes(ctx context.Context, index string, shards []uint64) ([]dax.ComputeNode, error)
|
||||
}
|
||||
|
||||
type MDSTopology struct {
|
||||
type ServerlessTopology struct {
|
||||
controller dax.Controller
|
||||
}
|
||||
|
||||
func (m *MDSTopology) ComputeNodes(ctx context.Context, index string, shards []uint64) ([]dax.ComputeNode, error) {
|
||||
func (m *ServerlessTopology) ComputeNodes(ctx context.Context, index string, shards []uint64) ([]dax.ComputeNode, error) {
|
||||
var daxShards = make(dax.ShardNums, len(shards))
|
||||
for i, s := range shards {
|
||||
daxShards[i] = dax.ShardNum(s)
|
||||
}
|
||||
|
||||
// TODO(tlt): this needs review; MDSTopology is converting from
|
||||
// TODO(tlt): this needs review; ServerlessTopology is converting from
|
||||
// string/uint64 to qtid/shardNum?? Perhaps we can get rid of the Topologer
|
||||
// interface altogether and replace it with dax.Noder.
|
||||
qtid := dax.TableKey(index).QualifiedTableID()
|
||||
|
|
@ -64,7 +64,7 @@ func (m *MDSTopology) ComputeNodes(ctx context.Context, index string, shards []u
|
|||
|
||||
// TODO(jaffee) we need version info in here ASAP. whenever schema or topo
|
||||
// changes, version gets bumped and nodes know to reject queries
|
||||
// and update their info from the MDS instead of querying it every
|
||||
// and update their info from the Controller instead of querying it every
|
||||
// time.
|
||||
type Translator interface {
|
||||
CreateIndexKeys(ctx context.Context, index string, keys []string) (map[string]uint64, error)
|
||||
|
|
@ -2177,7 +2177,7 @@ func (o *orchestrator) mapper(ctx context.Context, eg *errgroup.Group, ch chan m
|
|||
// replica) and a valid error from a healthy node. In the case of
|
||||
// the latter, there's no need to retry a replica, we should trust
|
||||
// the error from the healthy node and return that immediately.
|
||||
// TODO(jaffee) retries should contact MDS and find out who is up and has access to shards needed
|
||||
// TODO(jaffee) retries should contact Controller and find out who is up and has access to shards needed
|
||||
results, err := o.remoteExec(ctx, node.Address, index, &pql.Query{Calls: []*pql.Call{c}}, shards, embeddedRowsForNode)
|
||||
if len(results) > 0 {
|
||||
resp.result = results[0]
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import (
|
|||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/encoding/proto"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
idkmds "github.com/featurebasedb/featurebase/v3/idk/mds"
|
||||
idkserverless "github.com/featurebasedb/featurebase/v3/idk/serverless"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
featurebase_pql "github.com/featurebasedb/featurebase/v3/pql"
|
||||
fbproto "github.com/featurebasedb/featurebase/v3/proto"
|
||||
|
|
@ -82,8 +82,8 @@ func (q *Queryer) Orchestrator(qdbid dax.QualifiedDatabaseID) *qualifiedOrchestr
|
|||
|
||||
orch := &orchestrator{
|
||||
schema: sapi,
|
||||
trans: NewMDSTranslator(q.controller),
|
||||
topology: &MDSTopology{controller: q.controller},
|
||||
trans: NewServerlessTranslator(q.controller),
|
||||
topology: &ServerlessTopology{controller: q.controller},
|
||||
// TODO(jaffee) using default http.Client probably bad... need to set some timeouts.
|
||||
client: q.fbClient,
|
||||
logger: q.logger,
|
||||
|
|
@ -168,7 +168,7 @@ func (q *Queryer) QuerySQL(ctx context.Context, qdbid dax.QualifiedDatabaseID, s
|
|||
sapi := newQualifiedSchemaAPI(qdbid, q.controller)
|
||||
|
||||
// Importer
|
||||
imp := idkmds.NewImporter(q.controller, qdbid, nil)
|
||||
imp := idkserverless.NewImporter(q.controller, qdbid, nil)
|
||||
|
||||
// TODO(tlt): We need a dax-compatible implementation of the SystemAPI.
|
||||
sysapi := &featurebase.NopSystemAPI{}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
mdsclient "github.com/featurebasedb/featurebase/v3/dax/mds/client"
|
||||
controllerclient "github.com/featurebasedb/featurebase/v3/dax/controller/client"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/queryer"
|
||||
queryerhttp "github.com/featurebasedb/featurebase/v3/dax/queryer/http"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
|
|
@ -49,8 +49,8 @@ func (q *queryerService) HTTPHandler() http.Handler {
|
|||
return queryerhttp.Handler(q.queryer)
|
||||
}
|
||||
|
||||
func (q *queryerService) SetMDS(addr dax.Address) error {
|
||||
mdscli := mdsclient.New(addr, q.logger)
|
||||
q.queryer.SetController(mdscli)
|
||||
func (q *queryerService) SetController(addr dax.Address) error {
|
||||
controllercli := controllerclient.New(addr, q.logger)
|
||||
q.queryer.SetController(controllercli)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,21 +7,21 @@ import (
|
|||
pilosa "github.com/featurebasedb/featurebase/v3"
|
||||
featurebase_client "github.com/featurebasedb/featurebase/v3/client"
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller/partitioner"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/partitioner"
|
||||
"github.com/featurebasedb/featurebase/v3/disco"
|
||||
"github.com/featurebasedb/featurebase/v3/encoding/proto"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
)
|
||||
|
||||
// Ensure type implements interface.
|
||||
var _ Translator = (*mdsTranslator)(nil)
|
||||
var _ Translator = (*serverlessTranslator)(nil)
|
||||
|
||||
type mdsTranslator struct {
|
||||
type serverlessTranslator struct {
|
||||
controller dax.Controller
|
||||
}
|
||||
|
||||
func NewMDSTranslator(controller dax.Controller) *mdsTranslator {
|
||||
return &mdsTranslator{
|
||||
func NewServerlessTranslator(controller dax.Controller) *serverlessTranslator {
|
||||
return &serverlessTranslator{
|
||||
controller: controller,
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ func fbClient(address dax.Address) (*featurebase_client.Client, error) {
|
|||
)
|
||||
}
|
||||
|
||||
func (m *mdsTranslator) CreateIndexKeys(ctx context.Context, table string, keys []string) (map[string]uint64, error) {
|
||||
func (m *serverlessTranslator) CreateIndexKeys(ctx context.Context, table string, keys []string) (map[string]uint64, error) {
|
||||
tkey := dax.TableKey(table)
|
||||
qtid := tkey.QualifiedTableID()
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ func (m *mdsTranslator) CreateIndexKeys(ctx context.Context, table string, keys
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (m *mdsTranslator) CreateFieldKeys(ctx context.Context, table string, field string, keys []string) (map[string]uint64, error) {
|
||||
func (m *serverlessTranslator) CreateFieldKeys(ctx context.Context, table string, field string, keys []string) (map[string]uint64, error) {
|
||||
qtid := dax.TableKey(table).QualifiedTableID()
|
||||
address, err := m.controller.IngestPartition(ctx, qtid, dax.PartitionNum(0))
|
||||
if err != nil {
|
||||
|
|
@ -96,7 +96,7 @@ func (m *mdsTranslator) CreateFieldKeys(ctx context.Context, table string, field
|
|||
return fbClient.CreateFieldKeys(fld, keys...)
|
||||
}
|
||||
|
||||
func (m *mdsTranslator) FindIndexKeys(ctx context.Context, table string, keys []string) (map[string]uint64, error) {
|
||||
func (m *serverlessTranslator) FindIndexKeys(ctx context.Context, table string, keys []string) (map[string]uint64, error) {
|
||||
tkey := dax.TableKey(table)
|
||||
qtid := tkey.QualifiedTableID()
|
||||
|
||||
|
|
@ -149,7 +149,7 @@ func (m *mdsTranslator) FindIndexKeys(ctx context.Context, table string, keys []
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (m *mdsTranslator) FindFieldKeys(ctx context.Context, table, field string, keys []string) (map[string]uint64, error) {
|
||||
func (m *serverlessTranslator) FindFieldKeys(ctx context.Context, table, field string, keys []string) (map[string]uint64, error) {
|
||||
qtid := dax.TableKey(table).QualifiedTableID()
|
||||
address, err := m.controller.IngestPartition(ctx, qtid, dax.PartitionNum(0))
|
||||
if err != nil {
|
||||
|
|
@ -167,7 +167,7 @@ func (m *mdsTranslator) FindFieldKeys(ctx context.Context, table, field string,
|
|||
return fbClient.FindFieldKeys(fld, keys...)
|
||||
}
|
||||
|
||||
func (m *mdsTranslator) TranslateIndexIDs(ctx context.Context, index string, ids []uint64) ([]string, error) {
|
||||
func (m *serverlessTranslator) TranslateIndexIDs(ctx context.Context, index string, ids []uint64) ([]string, error) {
|
||||
idsByPartition := splitIDsByPartition(index, ids, 1<<20) // TODO(jaffee), don't hardcode shardwidth...need to get this from index info
|
||||
daxPartitions := make([]dax.PartitionNum, 0)
|
||||
for partition := range idsByPartition {
|
||||
|
|
@ -210,7 +210,7 @@ func (m *mdsTranslator) TranslateIndexIDs(ctx context.Context, index string, ids
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (m *mdsTranslator) TranslateIndexIDSet(ctx context.Context, table string, ids map[uint64]struct{}) (map[uint64]string, error) {
|
||||
func (m *serverlessTranslator) TranslateIndexIDSet(ctx context.Context, table string, ids map[uint64]struct{}) (map[uint64]string, error) {
|
||||
idList := make([]uint64, 0, len(ids))
|
||||
for id := range ids {
|
||||
idList = append(idList, id)
|
||||
|
|
@ -227,7 +227,7 @@ func (m *mdsTranslator) TranslateIndexIDSet(ctx context.Context, table string, i
|
|||
}
|
||||
return ret, nil
|
||||
}
|
||||
func (m *mdsTranslator) TranslateFieldIDs(ctx context.Context, tableKeyer dax.TableKeyer, field string, ids map[uint64]struct{}) (map[uint64]string, error) {
|
||||
func (m *serverlessTranslator) TranslateFieldIDs(ctx context.Context, tableKeyer dax.TableKeyer, field string, ids map[uint64]struct{}) (map[uint64]string, error) {
|
||||
idList := make([]uint64, 0, len(ids))
|
||||
for id := range ids {
|
||||
idList = append(idList, id)
|
||||
|
|
@ -248,7 +248,7 @@ func (m *mdsTranslator) TranslateFieldIDs(ctx context.Context, tableKeyer dax.Ta
|
|||
}
|
||||
return ret, nil
|
||||
}
|
||||
func (m *mdsTranslator) TranslateFieldListIDs(ctx context.Context, index, field string, ids []uint64) ([]string, error) {
|
||||
func (m *serverlessTranslator) TranslateFieldListIDs(ctx context.Context, index, field string, ids []uint64) ([]string, error) {
|
||||
qtid := dax.TableKey(index).QualifiedTableID()
|
||||
address, err := m.controller.IngestPartition(ctx, qtid, dax.PartitionNum(0))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/queryer"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
fbserver "github.com/featurebasedb/featurebase/v3/server"
|
||||
|
|
@ -43,14 +43,14 @@ type Config struct {
|
|||
// LogPath configures where Pilosa will write logs.
|
||||
LogPath string `toml:"log-path"`
|
||||
|
||||
MDS MDSOptions `toml:"mds"`
|
||||
Queryer QueryerOptions `toml:"queryer"`
|
||||
Computer ComputerOptions `toml:"computer"`
|
||||
Controller ControllerOptions `toml:"controller"`
|
||||
Queryer QueryerOptions `toml:"queryer"`
|
||||
Computer ComputerOptions `toml:"computer"`
|
||||
}
|
||||
|
||||
type MDSOptions struct {
|
||||
Run bool `toml:"run"`
|
||||
Config mds.Config `toml:"config"`
|
||||
type ControllerOptions struct {
|
||||
Run bool `toml:"run"`
|
||||
Config controller.Config `toml:"config"`
|
||||
}
|
||||
|
||||
type QueryerOptions struct {
|
||||
|
|
@ -67,8 +67,8 @@ type ComputerOptions struct {
|
|||
// NewConfig returns an instance of Config with default options.
|
||||
func NewConfig() *Config {
|
||||
c := &Config{
|
||||
MDS: MDSOptions{
|
||||
Config: mds.Config{
|
||||
Controller: ControllerOptions{
|
||||
Config: controller.Config{
|
||||
RegistrationBatchTimeout: time.Second * 3,
|
||||
StorageMethod: defaultStorageMethod,
|
||||
SnappingTurtleTimeout: time.Second * 10,
|
||||
|
|
|
|||
|
|
@ -25,10 +25,9 @@ import (
|
|||
featurebase "github.com/featurebasedb/featurebase/v3"
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
computersvc "github.com/featurebasedb/featurebase/v3/dax/computer/service"
|
||||
controllerhttp "github.com/featurebasedb/featurebase/v3/dax/controller/http"
|
||||
controllersvc "github.com/featurebasedb/featurebase/v3/dax/controller/service"
|
||||
daxhttp "github.com/featurebasedb/featurebase/v3/dax/http"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds"
|
||||
controllerhttp "github.com/featurebasedb/featurebase/v3/dax/mds/controller/http"
|
||||
mdssvc "github.com/featurebasedb/featurebase/v3/dax/mds/service"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/queryer"
|
||||
queryersvc "github.com/featurebasedb/featurebase/v3/dax/queryer/service"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
|
|
@ -277,20 +276,20 @@ func (m *Command) setupServer() error {
|
|||
|
||||
// setupServices uses the configuration to set up the configured services.
|
||||
func (m *Command) setupServices() error {
|
||||
// Set up MDS.
|
||||
if m.Config.MDS.Run {
|
||||
mdsCfg := m.Config.MDS.Config
|
||||
mdsCfg.Logger = m.logger
|
||||
mdsCfg.Director = controllerhttp.NewDirector(
|
||||
// Set up Controller.
|
||||
if m.Config.Controller.Run {
|
||||
controllerCfg := m.Config.Controller.Config
|
||||
controllerCfg.Logger = m.logger
|
||||
controllerCfg.Director = controllerhttp.NewDirector(
|
||||
controllerhttp.DirectorConfig{
|
||||
DirectivePath: "directive",
|
||||
SnapshotRequestPath: "snapshot",
|
||||
Logger: m.logger,
|
||||
})
|
||||
|
||||
m.svcmgr.MDS = mdssvc.New(m.advertiseURI, mds.New(mdsCfg))
|
||||
if err := m.svcmgr.MDSStart(); err != nil {
|
||||
return errors.Wrap(err, "starting mds service")
|
||||
m.svcmgr.Controller = controllersvc.New(m.advertiseURI, controllerCfg)
|
||||
if err := m.svcmgr.ControllerStart(); err != nil {
|
||||
return errors.Wrap(err, "starting controller service")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -302,18 +301,18 @@ func (m *Command) setupServices() error {
|
|||
|
||||
m.svcmgr.Queryer = queryersvc.New(m.advertiseURI, queryer.New(qryrCfg), m.logger)
|
||||
|
||||
var mdsAddr dax.Address
|
||||
if m.Config.Queryer.Config.MDSAddress != "" {
|
||||
mdsAddr = dax.Address(m.Config.Queryer.Config.MDSAddress)
|
||||
} else if m.svcmgr.MDS != nil {
|
||||
mdsAddr = m.svcmgr.MDS.Address()
|
||||
var controllerAddr dax.Address
|
||||
if m.Config.Queryer.Config.ControllerAddress != "" {
|
||||
controllerAddr = dax.Address(m.Config.Queryer.Config.ControllerAddress)
|
||||
} else if m.svcmgr.Controller != nil {
|
||||
controllerAddr = m.svcmgr.Controller.Address()
|
||||
} else {
|
||||
return errors.Errorf("queryer requires MDS")
|
||||
return errors.Errorf("queryer requires Controller")
|
||||
}
|
||||
|
||||
// Set MDS
|
||||
if err := m.svcmgr.Queryer.SetMDS(mdsAddr); err != nil {
|
||||
return errors.Wrap(err, "setting mds")
|
||||
// Set Controller
|
||||
if err := m.svcmgr.Queryer.SetController(controllerAddr); err != nil {
|
||||
return errors.Wrap(err, "setting controller")
|
||||
}
|
||||
|
||||
// Start queryer.
|
||||
|
|
@ -348,8 +347,8 @@ func (m *Command) setupServices() error {
|
|||
Logger: m.logger,
|
||||
}
|
||||
|
||||
if cfg.ComputerConfig.MDSAddress == "" && m.svcmgr.MDS != nil {
|
||||
cfg.ComputerConfig.MDSAddress = string(m.svcmgr.MDS.Address())
|
||||
if cfg.ComputerConfig.ControllerAddress == "" && m.svcmgr.Controller != nil {
|
||||
cfg.ComputerConfig.ControllerAddress = string(m.svcmgr.Controller.Address())
|
||||
}
|
||||
|
||||
// Add new computer service.
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ import (
|
|||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
computersvc "github.com/featurebasedb/featurebase/v3/dax/computer/service"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds"
|
||||
mdssvc "github.com/featurebasedb/featurebase/v3/dax/mds/service"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller"
|
||||
controllersvc "github.com/featurebasedb/featurebase/v3/dax/controller/service"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/queryer"
|
||||
queryersvc "github.com/featurebasedb/featurebase/v3/dax/queryer/service"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/server"
|
||||
|
|
@ -62,13 +62,13 @@ func (mc *ManagedCommand) Close() error {
|
|||
return mc.Command.Close()
|
||||
}
|
||||
|
||||
// NewMDS adds a new MDSService to the ManagedCommands ServiceManager.
|
||||
func (mc *ManagedCommand) NewMDS(cfg mds.Config) dax.ServiceKey {
|
||||
// NewController adds a new ControllerService to the ManagedCommands ServiceManager.
|
||||
func (mc *ManagedCommand) NewController(cfg controller.Config) dax.ServiceKey {
|
||||
uri := mc.URI()
|
||||
cfg.Logger = mc.svcmgr.Logger
|
||||
mc.svcmgr.MDS = mdssvc.New(uri, mds.New(cfg))
|
||||
mc.svcmgr.Controller = controllersvc.New(uri, cfg)
|
||||
|
||||
return dax.ServicePrefixMDS
|
||||
return dax.ServicePrefixController
|
||||
}
|
||||
|
||||
// NewQueryer adds a new QueryerService to the ManagedCommands ServiceManager.
|
||||
|
|
@ -78,16 +78,16 @@ func (mc *ManagedCommand) NewQueryer(cfg queryer.Config) dax.ServiceKey {
|
|||
cfg.Logger = logger
|
||||
mc.svcmgr.Queryer = queryersvc.New(uri, queryer.New(cfg), logger)
|
||||
|
||||
var mdsAddr dax.Address
|
||||
if cfg.MDSAddress != "" {
|
||||
mdsAddr = dax.Address(cfg.MDSAddress + "/" + dax.ServicePrefixMDS)
|
||||
} else if mc.svcmgr.MDS != nil {
|
||||
mdsAddr = mc.svcmgr.MDS.Address()
|
||||
var controllerAddr dax.Address
|
||||
if cfg.ControllerAddress != "" {
|
||||
controllerAddr = dax.Address(cfg.ControllerAddress + "/" + dax.ServicePrefixController)
|
||||
} else if mc.svcmgr.Controller != nil {
|
||||
controllerAddr = mc.svcmgr.Controller.Address()
|
||||
}
|
||||
|
||||
// Set MDS
|
||||
if err := mc.svcmgr.Queryer.SetMDS(mdsAddr); err != nil {
|
||||
logger.Panicf(errors.Wrap(err, "setting mds").Error())
|
||||
// Set Controller
|
||||
if err := mc.svcmgr.Queryer.SetController(controllerAddr); err != nil {
|
||||
logger.Panicf(errors.Wrap(err, "setting controller").Error())
|
||||
}
|
||||
|
||||
return dax.ServicePrefixQueryer
|
||||
|
|
@ -104,7 +104,7 @@ func (mc *ManagedCommand) NewComputer() dax.ServiceKey {
|
|||
Logger: mc.svcmgr.Logger,
|
||||
}
|
||||
|
||||
cfg.ComputerConfig.MDSAddress = mc.svcmgr.MDS.Address().String()
|
||||
cfg.ComputerConfig.ControllerAddress = mc.svcmgr.Controller.Address().String()
|
||||
|
||||
// Add new computer service.
|
||||
return mc.svcmgr.AddComputer(
|
||||
|
|
@ -186,12 +186,12 @@ func NewManagedCommand(tb fbtest.DirCleaner, opts ...server.CommandOption) *Mana
|
|||
mc.svcmgr = svcmgr
|
||||
|
||||
mc.Config.Bind = "http://localhost:0"
|
||||
mc.Config.MDS.Config.DataDir = path + "/mds"
|
||||
mc.Config.Controller.Config.DataDir = path + "/controller"
|
||||
mc.Config.Computer.Config.DataDir = path
|
||||
mc.Config.Computer.Config.WriteloggerDir = path + "/wl"
|
||||
mc.Config.MDS.Config.WriteloggerDir = path + "/wl"
|
||||
mc.Config.Controller.Config.WriteloggerDir = path + "/wl"
|
||||
mc.Config.Computer.Config.SnapshotterDir = path + "/sn"
|
||||
mc.Config.MDS.Config.SnapshotterDir = path + "/sn"
|
||||
mc.Config.Controller.Config.SnapshotterDir = path + "/sn"
|
||||
|
||||
return mc
|
||||
}
|
||||
|
|
@ -200,8 +200,8 @@ func NewManagedCommand(tb fbtest.DirCleaner, opts ...server.CommandOption) *Mana
|
|||
func DefaultConfig() *server.Config {
|
||||
cfg := server.NewConfig()
|
||||
cfg.Verbose = true
|
||||
cfg.MDS.Run = true
|
||||
cfg.MDS.Config.RegistrationBatchTimeout = 0
|
||||
cfg.Controller.Run = true
|
||||
cfg.Controller.Config.RegistrationBatchTimeout = 0
|
||||
cfg.Queryer.Run = true
|
||||
cfg.Computer.Run = true
|
||||
cfg.Computer.N = 1
|
||||
|
|
@ -231,7 +231,7 @@ func MustRunManagedCommand(tb testing.TB, opts ...server.CommandOption) *Managed
|
|||
}
|
||||
|
||||
if basic {
|
||||
assert.True(tb, mc.Healthy(dax.ServicePrefixMDS))
|
||||
assert.True(tb, mc.Healthy(dax.ServicePrefixController))
|
||||
assert.True(tb, mc.Healthy(dax.ServicePrefixQueryer))
|
||||
assert.True(tb, mc.Healthy(dax.ServicePrefixComputer+"0"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,11 @@ import (
|
|||
"net/http"
|
||||
"sync"
|
||||
|
||||
_ "net/http/pprof" // Imported for its side-effect of registering pprof endpoints with the server.
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
"github.com/felixge/fgprof"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
|
|
@ -20,9 +23,9 @@ type ServiceKey string
|
|||
type ServiceManager struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
// MDS
|
||||
MDS MDSService
|
||||
mdsStarted bool
|
||||
// Controller
|
||||
Controller ControllerService
|
||||
controllerStarted bool
|
||||
|
||||
// Queryer
|
||||
Queryer QueryerService
|
||||
|
|
@ -62,9 +65,9 @@ func (s *ServiceManager) HTTPHandler() http.Handler {
|
|||
|
||||
// StartAll starts all services which have been added to ServiceManager.
|
||||
func (s *ServiceManager) StartAll() error {
|
||||
// MDS
|
||||
if err := s.MDSStart(); err != nil {
|
||||
return errors.Wrap(err, "starting mds")
|
||||
// Controller
|
||||
if err := s.ControllerStart(); err != nil {
|
||||
return errors.Wrap(err, "starting controller")
|
||||
}
|
||||
|
||||
// Queryer
|
||||
|
|
@ -91,51 +94,51 @@ func (s *ServiceManager) StopAll() error {
|
|||
if err := s.QueryerStop(); err != nil {
|
||||
s.Logger.Printf("stopping queryer: %v", err)
|
||||
}
|
||||
return s.MDSStop()
|
||||
return s.ControllerStop()
|
||||
}
|
||||
|
||||
// MDSStart starts the MDS service.
|
||||
func (s *ServiceManager) MDSStart() error {
|
||||
if s.MDS == nil {
|
||||
// ControllerStart starts the Controller service.
|
||||
func (s *ServiceManager) ControllerStart() error {
|
||||
if s.Controller == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if s.mdsStarted {
|
||||
if s.controllerStarted {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.mdsStarted = true
|
||||
s.controllerStarted = true
|
||||
s.resetRouter()
|
||||
|
||||
if err := s.MDS.Start(); err != nil {
|
||||
s.mdsStarted = false
|
||||
return errors.Wrap(err, "starting mds")
|
||||
if err := s.Controller.Start(); err != nil {
|
||||
s.controllerStarted = false
|
||||
return errors.Wrap(err, "starting controller")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MDSStop stops the MDS service.
|
||||
func (s *ServiceManager) MDSStop() error {
|
||||
if s.MDS == nil {
|
||||
// ControllerStop stops the Controller service.
|
||||
func (s *ServiceManager) ControllerStop() error {
|
||||
if s.Controller == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if !s.mdsStarted {
|
||||
if !s.controllerStarted {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.mdsStarted = false
|
||||
s.controllerStarted = false
|
||||
s.resetRouter()
|
||||
|
||||
if err := s.MDS.Stop(); err != nil {
|
||||
s.mdsStarted = true
|
||||
if err := s.Controller.Stop(); err != nil {
|
||||
s.controllerStarted = true
|
||||
return errors.Wrap(err, "stopping controller")
|
||||
}
|
||||
|
||||
|
|
@ -313,12 +316,14 @@ func (s *ServiceManager) resetRouter() {
|
|||
func (s *ServiceManager) buildRouter() *mux.Router {
|
||||
router := mux.NewRouter()
|
||||
router.HandleFunc("/health", getHealth).Methods("GET").Name("GetHealth")
|
||||
router.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux).Methods("GET")
|
||||
router.PathPrefix("/debug/fgprof").Handler(fgprof.Handler()).Methods("GET")
|
||||
|
||||
// MDS.
|
||||
if s.MDS != nil && s.mdsStarted {
|
||||
pre := "/" + ServicePrefixMDS
|
||||
// Controller.
|
||||
if s.Controller != nil && s.controllerStarted {
|
||||
pre := "/" + ServicePrefixController
|
||||
router.PathPrefix(pre + "/").Handler(
|
||||
http.StripPrefix(pre, s.MDS.HTTPHandler()))
|
||||
http.StripPrefix(pre, s.Controller.HTTPHandler()))
|
||||
}
|
||||
|
||||
// Computers.
|
||||
|
|
@ -363,20 +368,20 @@ type MultiService interface {
|
|||
Key() ServiceKey
|
||||
}
|
||||
|
||||
type MDSService interface {
|
||||
type ControllerService interface {
|
||||
Service
|
||||
}
|
||||
|
||||
type ComputerService interface {
|
||||
MultiService
|
||||
|
||||
SetMDS(Address) error
|
||||
SetController(Address) error
|
||||
}
|
||||
|
||||
type QueryerService interface {
|
||||
Service
|
||||
|
||||
SetMDS(Address) error
|
||||
SetController(Address) error
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
featurebase "github.com/featurebasedb/featurebase/v3"
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
mdsclient "github.com/featurebasedb/featurebase/v3/dax/mds/client"
|
||||
controllerclient "github.com/featurebasedb/featurebase/v3/dax/controller/client"
|
||||
queryerclient "github.com/featurebasedb/featurebase/v3/dax/queryer/client"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/server"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/server/test"
|
||||
|
|
@ -63,20 +63,20 @@ func TestDAXIntegration(t *testing.T) {
|
|||
|
||||
svcmgr := mc.Manage()
|
||||
|
||||
var mdsKey dax.ServiceKey
|
||||
var controllerKey dax.ServiceKey
|
||||
var queryerKey dax.ServiceKey
|
||||
var computerKey0 dax.ServiceKey
|
||||
var computerKey1 dax.ServiceKey
|
||||
|
||||
assert.False(t, mc.Healthy(mdsKey))
|
||||
assert.False(t, mc.Healthy(controllerKey))
|
||||
assert.False(t, mc.Healthy(queryerKey))
|
||||
assert.False(t, mc.Healthy(computerKey0))
|
||||
assert.False(t, mc.Healthy(computerKey1))
|
||||
|
||||
// Start MDS.
|
||||
mdsKey = mc.NewMDS(cfg.MDS.Config)
|
||||
assert.NoError(t, svcmgr.MDSStart())
|
||||
assert.True(t, mc.Healthy(mdsKey))
|
||||
// Start Controller.
|
||||
controllerKey = mc.NewController(cfg.Controller.Config)
|
||||
assert.NoError(t, svcmgr.ControllerStart())
|
||||
assert.True(t, mc.Healthy(controllerKey))
|
||||
assert.False(t, mc.Healthy(queryerKey))
|
||||
assert.False(t, mc.Healthy(computerKey0))
|
||||
assert.False(t, mc.Healthy(computerKey1))
|
||||
|
|
@ -84,7 +84,7 @@ func TestDAXIntegration(t *testing.T) {
|
|||
// Start Queryer.
|
||||
queryerKey = mc.NewQueryer(cfg.Queryer.Config)
|
||||
assert.NoError(t, svcmgr.QueryerStart())
|
||||
assert.True(t, mc.Healthy(mdsKey))
|
||||
assert.True(t, mc.Healthy(controllerKey))
|
||||
assert.True(t, mc.Healthy(queryerKey))
|
||||
assert.False(t, mc.Healthy(computerKey0))
|
||||
assert.False(t, mc.Healthy(computerKey1))
|
||||
|
|
@ -92,7 +92,7 @@ func TestDAXIntegration(t *testing.T) {
|
|||
// New and Start Computer 0.
|
||||
computerKey0 = mc.NewComputer()
|
||||
assert.NoError(t, svcmgr.ComputerStart(computerKey0))
|
||||
assert.True(t, mc.Healthy(mdsKey))
|
||||
assert.True(t, mc.Healthy(controllerKey))
|
||||
assert.True(t, mc.Healthy(queryerKey))
|
||||
assert.True(t, mc.Healthy(computerKey0))
|
||||
assert.False(t, mc.Healthy(computerKey1))
|
||||
|
|
@ -100,14 +100,14 @@ func TestDAXIntegration(t *testing.T) {
|
|||
// New and Start Computer 1.
|
||||
computerKey1 = mc.NewComputer()
|
||||
assert.NoError(t, svcmgr.ComputerStart(computerKey1))
|
||||
assert.True(t, mc.Healthy(mdsKey))
|
||||
assert.True(t, mc.Healthy(controllerKey))
|
||||
assert.True(t, mc.Healthy(queryerKey))
|
||||
assert.True(t, mc.Healthy(computerKey0))
|
||||
assert.True(t, mc.Healthy(computerKey1))
|
||||
|
||||
// Stop Computer 1.
|
||||
assert.NoError(t, svcmgr.ComputerStop(computerKey0))
|
||||
assert.True(t, mc.Healthy(mdsKey))
|
||||
assert.True(t, mc.Healthy(controllerKey))
|
||||
assert.True(t, mc.Healthy(queryerKey))
|
||||
assert.False(t, mc.Healthy(computerKey0))
|
||||
assert.True(t, mc.Healthy(computerKey1))
|
||||
|
|
@ -120,13 +120,13 @@ func TestDAXIntegration(t *testing.T) {
|
|||
|
||||
svcmgr := mc.Manage()
|
||||
|
||||
// Set up MDS client.
|
||||
mdsClient := mdsclient.New(svcmgr.MDS.Address(), svcmgr.Logger)
|
||||
// Set up Controller client.
|
||||
controllerClient := controllerclient.New(svcmgr.Controller.Address(), svcmgr.Logger)
|
||||
|
||||
// Create database.
|
||||
qdb.Options.WorkersMin = 1
|
||||
qdb.Options.WorkersMax = 1
|
||||
assert.NoError(t, mdsClient.CreateDatabase(context.Background(), qdb))
|
||||
assert.NoError(t, controllerClient.CreateDatabase(context.Background(), qdb))
|
||||
|
||||
// skips is a list of tests which are currently not passing in dax. We
|
||||
// need to get these passing before alpha.
|
||||
|
|
@ -194,13 +194,13 @@ func TestDAXIntegration(t *testing.T) {
|
|||
|
||||
svcmgr := mc.Manage()
|
||||
|
||||
// Set up MDS client.
|
||||
mdsClient := mdsclient.New(svcmgr.MDS.Address(), svcmgr.Logger)
|
||||
// Set up Controller client.
|
||||
controllerClient := controllerclient.New(svcmgr.Controller.Address(), svcmgr.Logger)
|
||||
|
||||
// Create database.
|
||||
qdb.Options.WorkersMin = 1
|
||||
qdb.Options.WorkersMax = 1
|
||||
assert.NoError(t, mdsClient.CreateDatabase(context.Background(), qdb))
|
||||
assert.NoError(t, controllerClient.CreateDatabase(context.Background(), qdb))
|
||||
|
||||
runTableTests(t,
|
||||
mc.Manage().Queryer.Address(),
|
||||
|
|
@ -216,13 +216,13 @@ func TestDAXIntegration(t *testing.T) {
|
|||
|
||||
svcmgr := mc.Manage()
|
||||
|
||||
// Set up MDS client.
|
||||
mdsClient := mdsclient.New(svcmgr.MDS.Address(), svcmgr.Logger)
|
||||
// Set up Controller client.
|
||||
controllerClient := controllerclient.New(svcmgr.Controller.Address(), svcmgr.Logger)
|
||||
|
||||
// Create database.
|
||||
qdb.Options.WorkersMin = 2
|
||||
qdb.Options.WorkersMax = 2
|
||||
assert.NoError(t, mdsClient.CreateDatabase(context.Background(), qdb))
|
||||
assert.NoError(t, controllerClient.CreateDatabase(context.Background(), qdb))
|
||||
|
||||
computers := svcmgr.Computers()
|
||||
computerKey0 := dax.ServiceKey(dax.ServicePrefixComputer + "0")
|
||||
|
|
@ -234,7 +234,7 @@ func TestDAXIntegration(t *testing.T) {
|
|||
basicTableTestConfig(qdbid, defs.Keyed)...,
|
||||
)
|
||||
|
||||
qtid, err := mdsClient.TableID(context.Background(), qdbid, dax.TableName(defs.Keyed.Name(0)))
|
||||
qtid, err := controllerClient.TableID(context.Background(), qdbid, dax.TableName(defs.Keyed.Name(0)))
|
||||
assert.NoError(t, err)
|
||||
|
||||
// ensure partitions are covered
|
||||
|
|
@ -243,7 +243,7 @@ func TestDAXIntegration(t *testing.T) {
|
|||
allPartitions := append(partitions0, partitions1...)
|
||||
sort.Sort(allPartitions)
|
||||
|
||||
nodes, err := mdsClient.TranslateNodes(context.Background(), qtid, allPartitions...)
|
||||
nodes, err := controllerClient.TranslateNodes(context.Background(), qtid, allPartitions...)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, nodes, 2) {
|
||||
// computer0 (node0)
|
||||
|
|
@ -262,7 +262,7 @@ func TestDAXIntegration(t *testing.T) {
|
|||
time.Sleep(5 * time.Second)
|
||||
|
||||
// ensure paritions are still covered
|
||||
nodes, err = mdsClient.TranslateNodes(context.Background(), qtid, append(partitions0, partitions1...)...)
|
||||
nodes, err = controllerClient.TranslateNodes(context.Background(), qtid, append(partitions0, partitions1...)...)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, nodes, 1) {
|
||||
// computer1 (node0)
|
||||
|
|
@ -277,13 +277,13 @@ func TestDAXIntegration(t *testing.T) {
|
|||
|
||||
svcmgr := mc.Manage()
|
||||
|
||||
// Set up MDS client.
|
||||
mdsClient := mdsclient.New(svcmgr.MDS.Address(), svcmgr.Logger)
|
||||
// Set up Controller client.
|
||||
controllerClient := controllerclient.New(svcmgr.Controller.Address(), svcmgr.Logger)
|
||||
|
||||
// Create database.
|
||||
qdb.Options.WorkersMin = 1
|
||||
qdb.Options.WorkersMax = 1
|
||||
assert.NoError(t, mdsClient.CreateDatabase(context.Background(), qdb))
|
||||
assert.NoError(t, controllerClient.CreateDatabase(context.Background(), qdb))
|
||||
|
||||
computerKey0 := dax.ServiceKey(dax.ServicePrefixComputer + "0")
|
||||
|
||||
|
|
@ -331,13 +331,13 @@ func TestDAXIntegration(t *testing.T) {
|
|||
|
||||
svcmgr := mc.Manage()
|
||||
|
||||
// Set up MDS client.
|
||||
mdsClient := mdsclient.New(svcmgr.MDS.Address(), svcmgr.Logger)
|
||||
// Set up Controller client.
|
||||
controllerClient := controllerclient.New(svcmgr.Controller.Address(), svcmgr.Logger)
|
||||
|
||||
// Create database.
|
||||
qdb.Options.WorkersMin = 1
|
||||
qdb.Options.WorkersMax = 1
|
||||
assert.NoError(t, mdsClient.CreateDatabase(context.Background(), qdb))
|
||||
assert.NoError(t, controllerClient.CreateDatabase(context.Background(), qdb))
|
||||
|
||||
computerKey0 := dax.ServiceKey(dax.ServicePrefixComputer + "0")
|
||||
|
||||
|
|
@ -355,10 +355,10 @@ func TestDAXIntegration(t *testing.T) {
|
|||
|
||||
// Snapshot table
|
||||
ctx := context.Background()
|
||||
qtid, err := mdsClient.TableID(ctx, qdbid, dax.TableName(defs.Keyed.Name(0)))
|
||||
qtid, err := controllerClient.TableID(ctx, qdbid, dax.TableName(defs.Keyed.Name(0)))
|
||||
assert.NoError(t, err)
|
||||
|
||||
mdsClient.SnapshotTable(ctx, qtid)
|
||||
controllerClient.SnapshotTable(ctx, qtid)
|
||||
|
||||
// Ingest more data.
|
||||
t.Run("ingest and query more data", func(t *testing.T) {
|
||||
|
|
@ -403,24 +403,24 @@ func TestDAXIntegration(t *testing.T) {
|
|||
})
|
||||
})
|
||||
|
||||
t.Run("MDS_Persistence", func(t *testing.T) {
|
||||
t.Run("Controller_Persistence", func(t *testing.T) {
|
||||
mc := test.MustRunManagedCommand(t)
|
||||
defer mc.Close()
|
||||
|
||||
svcmgr := mc.Manage()
|
||||
|
||||
// Set up MDS client.
|
||||
mdsClient := mdsclient.New(svcmgr.MDS.Address(), svcmgr.Logger)
|
||||
// Set up Controller client.
|
||||
controllerClient := controllerclient.New(svcmgr.Controller.Address(), svcmgr.Logger)
|
||||
|
||||
// Create database.
|
||||
qdb.Options.WorkersMin = 1
|
||||
qdb.Options.WorkersMax = 1
|
||||
assert.NoError(t, mdsClient.CreateDatabase(context.Background(), qdb))
|
||||
assert.NoError(t, controllerClient.CreateDatabase(context.Background(), qdb))
|
||||
|
||||
computerKey0 := dax.ServiceKey(dax.ServicePrefixComputer + "0")
|
||||
|
||||
mdsKey := dax.ServiceKey(dax.ServicePrefixMDS)
|
||||
assert.True(t, mc.Healthy(mdsKey))
|
||||
controllerKey := dax.ServiceKey(dax.ServicePrefixController)
|
||||
assert.True(t, mc.Healthy(controllerKey))
|
||||
|
||||
// Ingest and query some data.
|
||||
runTableTests(t,
|
||||
|
|
@ -428,13 +428,13 @@ func TestDAXIntegration(t *testing.T) {
|
|||
basicTableTestConfig(qdbid, defs.Keyed)...,
|
||||
)
|
||||
|
||||
qtid, err := mdsClient.TableID(context.Background(), qdbid, dax.TableName(defs.Keyed.Name(0)))
|
||||
qtid, err := controllerClient.TableID(context.Background(), qdbid, dax.TableName(defs.Keyed.Name(0)))
|
||||
assert.NoError(t, err)
|
||||
|
||||
// ensure partitions are covered
|
||||
partitions := dax.PartitionNums{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
|
||||
|
||||
nodes, err := mdsClient.TranslateNodes(context.Background(), qtid, partitions...)
|
||||
nodes, err := controllerClient.TranslateNodes(context.Background(), qtid, partitions...)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, nodes, 1) {
|
||||
// computer0 (node0)
|
||||
|
|
@ -442,17 +442,17 @@ func TestDAXIntegration(t *testing.T) {
|
|||
assert.Equal(t, partitions, nodes[0].Partitions)
|
||||
}
|
||||
|
||||
// Stop MDS.
|
||||
assert.NoError(t, svcmgr.MDSStop())
|
||||
assert.False(t, mc.Healthy(mdsKey))
|
||||
// Stop Controller.
|
||||
assert.NoError(t, svcmgr.ControllerStop())
|
||||
assert.False(t, mc.Healthy(controllerKey))
|
||||
|
||||
// Start New MDS.
|
||||
mdsKey = mc.NewMDS(mc.Config.MDS.Config)
|
||||
assert.NoError(t, svcmgr.MDSStart())
|
||||
assert.True(t, mc.Healthy(mdsKey))
|
||||
// Start New Controller.
|
||||
controllerKey = mc.NewController(mc.Config.Controller.Config)
|
||||
assert.NoError(t, svcmgr.ControllerStart())
|
||||
assert.True(t, mc.Healthy(controllerKey))
|
||||
|
||||
// ensure paritions are still covered
|
||||
nodes, err = mdsClient.TranslateNodes(context.Background(), qtid, partitions...)
|
||||
nodes, err = controllerClient.TranslateNodes(context.Background(), qtid, partitions...)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, nodes, 1) {
|
||||
// computer0 (node0)
|
||||
|
|
@ -467,13 +467,13 @@ func TestDAXIntegration(t *testing.T) {
|
|||
|
||||
svcmgr := mc.Manage()
|
||||
|
||||
// Set up MDS client.
|
||||
mdsClient := mdsclient.New(svcmgr.MDS.Address(), svcmgr.Logger)
|
||||
// Set up Controller client.
|
||||
controllerClient := controllerclient.New(svcmgr.Controller.Address(), svcmgr.Logger)
|
||||
|
||||
// Create database.
|
||||
qdb.Options.WorkersMin = 1
|
||||
qdb.Options.WorkersMax = 1
|
||||
assert.NoError(t, mdsClient.CreateDatabase(context.Background(), qdb))
|
||||
assert.NoError(t, controllerClient.CreateDatabase(context.Background(), qdb))
|
||||
|
||||
computerKey0 := dax.ServiceKey(dax.ServicePrefixComputer + "0")
|
||||
|
||||
|
|
@ -520,13 +520,13 @@ func TestDAXIntegration(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
// Set up MDS client.
|
||||
mdsClient := mdsclient.New(svcmgr.MDS.Address(), svcmgr.Logger)
|
||||
// Set up Controller client.
|
||||
controllerClient := controllerclient.New(svcmgr.Controller.Address(), svcmgr.Logger)
|
||||
|
||||
// Create database.
|
||||
qdb.Options.WorkersMin = 1
|
||||
qdb.Options.WorkersMax = 1
|
||||
assert.NoError(t, mdsClient.CreateDatabase(context.Background(), qdb))
|
||||
assert.NoError(t, controllerClient.CreateDatabase(context.Background(), qdb))
|
||||
|
||||
// Create two tables with data. Query the data to ensure it exists.
|
||||
runTableTests(t,
|
||||
|
|
@ -535,23 +535,23 @@ func TestDAXIntegration(t *testing.T) {
|
|||
)
|
||||
|
||||
// Make sure the database and tables exist.
|
||||
db, err := mdsClient.DatabaseByName(ctx, orgID, dbname)
|
||||
db, err := controllerClient.DatabaseByName(ctx, orgID, dbname)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, db)
|
||||
|
||||
tbl1, err := mdsClient.TableByName(ctx, qdbid, dax.TableName(defs.Keyed.Name(0)))
|
||||
tbl1, err := controllerClient.TableByName(ctx, qdbid, dax.TableName(defs.Keyed.Name(0)))
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, tbl1)
|
||||
|
||||
tbl2, err := mdsClient.TableByName(ctx, qdbid, dax.TableName(defs.Unkeyed.Name(0)))
|
||||
tbl2, err := controllerClient.TableByName(ctx, qdbid, dax.TableName(defs.Unkeyed.Name(0)))
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, tbl2)
|
||||
|
||||
// Drop the database
|
||||
assert.NoError(t, mdsClient.DropDatabase(ctx, qdbid))
|
||||
assert.NoError(t, controllerClient.DropDatabase(ctx, qdbid))
|
||||
|
||||
// Make sure the database and tables no longer exist.
|
||||
db, err = mdsClient.DatabaseByName(ctx, orgID, dbname)
|
||||
db, err = controllerClient.DatabaseByName(ctx, orgID, dbname)
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), "database name 'dbname1' does not exist")
|
||||
// TODO(tlt): replace the previous line with the following once we
|
||||
|
|
@ -560,7 +560,7 @@ func TestDAXIntegration(t *testing.T) {
|
|||
}
|
||||
assert.Nil(t, db)
|
||||
|
||||
tbl1, err = mdsClient.TableByName(ctx, qdbid, dax.TableName(defs.Keyed.Name(0)))
|
||||
tbl1, err = controllerClient.TableByName(ctx, qdbid, dax.TableName(defs.Keyed.Name(0)))
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), "table name 'keyed' does not exist")
|
||||
// TODO(tlt): replace the previous line with the following once we
|
||||
|
|
@ -569,7 +569,7 @@ func TestDAXIntegration(t *testing.T) {
|
|||
}
|
||||
assert.Nil(t, tbl1)
|
||||
|
||||
tbl2, err = mdsClient.TableByName(ctx, qdbid, dax.TableName(defs.Unkeyed.Name(0)))
|
||||
tbl2, err = controllerClient.TableByName(ctx, qdbid, dax.TableName(defs.Unkeyed.Name(0)))
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), "table name 'unkeyed' does not exist")
|
||||
// TODO(tlt): replace the previous line with the following once we
|
||||
|
|
@ -584,13 +584,13 @@ func TestDAXIntegration(t *testing.T) {
|
|||
defer mc.Close()
|
||||
svcmgr := mc.Manage()
|
||||
|
||||
// Set up MDS client.
|
||||
mdsClient := mdsclient.New(svcmgr.MDS.Address(), svcmgr.Logger)
|
||||
// Set up Controller client.
|
||||
controllerClient := controllerclient.New(svcmgr.Controller.Address(), svcmgr.Logger)
|
||||
|
||||
// Create database.
|
||||
qdb.Options.WorkersMin = 1
|
||||
qdb.Options.WorkersMax = 1
|
||||
assert.NoError(t, mdsClient.CreateDatabase(context.Background(), qdb))
|
||||
assert.NoError(t, controllerClient.CreateDatabase(context.Background(), qdb))
|
||||
|
||||
testconfigs := basicTableTestConfig(qdbid, defs.Keyed)
|
||||
for i := range testconfigs {
|
||||
|
|
@ -606,7 +606,7 @@ func TestDAXIntegration(t *testing.T) {
|
|||
// Ensure the index and writelogger directories are empty.
|
||||
assert.False(t, dirIsEmpty(t, rootDir+"/computer0"))
|
||||
assert.False(t, dirIsEmpty(t, rootDir+"/computer0/indexes"))
|
||||
assert.False(t, dirIsEmpty(t, rootDir+"/mds"))
|
||||
assert.False(t, dirIsEmpty(t, rootDir+"/controller"))
|
||||
assert.False(t, dirIsEmpty(t, rootDir+"/wl"))
|
||||
|
||||
resp := runSQL(t, svcmgr.Queryer.Address(), testconfigs[0].qdbid, "drop table keyed")
|
||||
|
|
@ -615,7 +615,7 @@ func TestDAXIntegration(t *testing.T) {
|
|||
// Ensure the index and writelogger directories are empty.
|
||||
assert.False(t, dirIsEmpty(t, rootDir+"/computer0"))
|
||||
assert.True(t, dirIsEmpty(t, rootDir+"/computer0/indexes"))
|
||||
assert.False(t, dirIsEmpty(t, rootDir+"/mds"))
|
||||
assert.False(t, dirIsEmpty(t, rootDir+"/controller"))
|
||||
assert.True(t, dirIsEmpty(t, rootDir+"/wl"))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/schemar"
|
||||
schemarbolt "github.com/featurebasedb/featurebase/v3/dax/mds/schemar/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/schemar"
|
||||
schemarbolt "github.com/featurebasedb/featurebase/v3/dax/controller/schemar/boltdb"
|
||||
testbolt "github.com/featurebasedb/featurebase/v3/dax/test/boltdb"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
)
|
||||
|
|
|
|||
10
holder.go
10
holder.go
|
|
@ -137,11 +137,11 @@ type Holder struct {
|
|||
directive *dax.Directive
|
||||
|
||||
// directiveApplied is used for testing (in an attempt to avoid sleeps). It
|
||||
// should be removed once we sort out the logic between MDS and computer
|
||||
// nodes. For example, MDS really needs to send out directives
|
||||
// asynchronously and allow a computer to load data from
|
||||
// snapshotter/writelogger; then MDS should only start directing queries to
|
||||
// that computer once it has completed applying the snapshot.
|
||||
// should be removed once we sort out the logic between controller and
|
||||
// computer nodes. For example, the Controller really needs to send out
|
||||
// directives asynchronously and allow a computer to load data from
|
||||
// snapshotter/writelogger; then the Controller should only start directing
|
||||
// queries to that computer once it has completed applying the snapshot.
|
||||
directiveApplied bool
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const (
|
|||
TargetFeaturebase = "featurebase"
|
||||
TargetKafka = "kafka"
|
||||
TargetKafkaStatic = "kafkastatic"
|
||||
TargetMDS = "mds"
|
||||
TargetServerless = "serverless"
|
||||
)
|
||||
|
||||
// Main is the top-level datagen struct. It represents datagen-specific
|
||||
|
|
@ -61,7 +61,7 @@ type Main struct {
|
|||
// Used strictly for configuration of the targets.
|
||||
Pilosa PilosaConfig
|
||||
Kafka KafkaConfig
|
||||
MDS MDSConfig
|
||||
Serverless ServerlessConfig
|
||||
FeatureBase FeatureBaseConfig `flag:"featurebase" help:"qualified featurebase table"`
|
||||
|
||||
DryRun bool `help:"Dry run - just flag parsing."`
|
||||
|
|
@ -103,11 +103,11 @@ type KafkaConfig struct {
|
|||
NumPartitions int `short:"" help:"set partition for kafka cluster"`
|
||||
}
|
||||
|
||||
// MDSConfig represents the configuration options to be used when target = mds.
|
||||
// These are really just a sub-set of idk.Main, containing only those arguments
|
||||
// that really apply to datagen.
|
||||
type MDSConfig struct {
|
||||
Address string `short:"" help:"MDS host:port to connect to"`
|
||||
// ServerlessConfig represents the configuration options to be used when target
|
||||
// = serverless. These are really just a sub-set of idk.Main, containing only
|
||||
// those arguments that really apply to datagen.
|
||||
type ServerlessConfig struct {
|
||||
Address string `short:"" help:"Controller host:port to connect to"`
|
||||
}
|
||||
|
||||
// NewMain returns a new instance of Main.
|
||||
|
|
@ -286,7 +286,7 @@ func (m *Main) Preload() error {
|
|||
m.KafkaPut.FBIDField = m.idkMain.IDField
|
||||
m.KafkaPut.FBIndexName = m.Pilosa.Index
|
||||
|
||||
case TargetMDS:
|
||||
case TargetServerless:
|
||||
m.idkMain.Namespace = "ingester_datagen"
|
||||
m.idkMain.Concurrency = m.Concurrency
|
||||
m.idkMain.CacheLength = m.Pilosa.CacheLength
|
||||
|
|
@ -298,8 +298,8 @@ func (m *Main) Preload() error {
|
|||
m.idkMain.BatchSize = m.Pilosa.BatchSize
|
||||
}
|
||||
|
||||
// MDS-specific
|
||||
m.idkMain.MDSAddress = m.MDS.Address
|
||||
// Serverless-specific
|
||||
m.idkMain.ControllerAddress = m.Serverless.Address
|
||||
m.idkMain.OrganizationID = dax.OrganizationID(m.FeatureBase.OrganizationID)
|
||||
m.idkMain.DatabaseID = dax.DatabaseID(m.FeatureBase.DatabaseID)
|
||||
m.idkMain.TableName = dax.TableName(m.FeatureBase.TableName)
|
||||
|
|
|
|||
|
|
@ -141,8 +141,8 @@ services:
|
|||
FEATUREBASE_BIND: 0.0.0.0:8080
|
||||
FEATUREBASE_VERBOSE: "true"
|
||||
FEATUREBASE_QUERYER_RUN: "true"
|
||||
FEATUREBASE_MDS_RUN: "true"
|
||||
FEATUREBASE_MDS_CONFIG_DATA_DIR: /dax-data/mds
|
||||
FEATUREBASE_CONTROLLER_RUN: "true"
|
||||
FEATUREBASE_CONTROLLER_CONFIG_DATA_DIR: /dax-data/controller
|
||||
FEATUREBASE_COMPUTER_RUN: "true"
|
||||
FEATUREBASE_COMPUTER_CONFIG_DATA_DIR: /dax-data/computer
|
||||
FEATUREBASE_COMPUTER_CONFIG_WRITELOGGER_DIR: /dax-data/wl
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ import (
|
|||
pilosaclient "github.com/featurebasedb/featurebase/v3/client"
|
||||
client_types "github.com/featurebasedb/featurebase/v3/client/types"
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
mdsclient "github.com/featurebasedb/featurebase/v3/dax/mds/client"
|
||||
"github.com/featurebasedb/featurebase/v3/idk/mds"
|
||||
controllerclient "github.com/featurebasedb/featurebase/v3/dax/controller/client"
|
||||
"github.com/featurebasedb/featurebase/v3/idk/serverless"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
"github.com/featurebasedb/featurebase/v3/pql"
|
||||
proto "github.com/featurebasedb/featurebase/v3/proto"
|
||||
|
|
@ -97,10 +97,10 @@ type Main struct {
|
|||
|
||||
UseShardTransactionalEndpoint bool `flag:"use-shard-transactional-endpoint" help:"Use alternate import endpoint that ingests data for all fields in a shard in a single atomic request. No negative performance impact and better consistency. Recommended."`
|
||||
|
||||
MDSAddress string `short:"" help:"MDS address."`
|
||||
OrganizationID dax.OrganizationID `short:"" help:"auto-assigned organization ID"`
|
||||
DatabaseID dax.DatabaseID `short:"" help:"auto-assigned database ID"`
|
||||
TableName dax.TableName `short:"" help:"human friendly table name"`
|
||||
ControllerAddress string `short:"" help:"Controller address."`
|
||||
OrganizationID dax.OrganizationID `short:"" help:"auto-assigned organization ID"`
|
||||
DatabaseID dax.DatabaseID `short:"" help:"auto-assigned database ID"`
|
||||
TableName dax.TableName `short:"" help:"human friendly table name"`
|
||||
|
||||
csvWriter *csv.Writer
|
||||
csvFile *os.File
|
||||
|
|
@ -984,7 +984,7 @@ func (m *Main) setupClient() (*tls.Config, error) {
|
|||
)
|
||||
}
|
||||
|
||||
if m.useMDS() {
|
||||
if m.useController() {
|
||||
// We should only have one "pilosa host" here. Get the path from that
|
||||
// and use it as the client path prefix.
|
||||
var prefix string
|
||||
|
|
@ -1003,28 +1003,28 @@ func (m *Main) setupClient() (*tls.Config, error) {
|
|||
}
|
||||
|
||||
// Set up the SchemaManager
|
||||
if m.useMDS() {
|
||||
if m.useController() {
|
||||
ctx := context.Background()
|
||||
|
||||
// MDS doesn't auto-create a table based on IDK ingest; the table must
|
||||
// already exist.
|
||||
mdsClient := mdsclient.New(dax.Address(m.MDSAddress), m.log)
|
||||
// Controller doesn't auto-create a table based on IDK ingest; the table
|
||||
// must already exist.
|
||||
controllerClient := controllerclient.New(dax.Address(m.ControllerAddress), m.log)
|
||||
qdbid := dax.NewQualifiedDatabaseID(m.OrganizationID, m.DatabaseID)
|
||||
qtid, err := mdsClient.TableID(ctx, qdbid, m.TableName)
|
||||
qtid, err := controllerClient.TableID(ctx, qdbid, m.TableName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getting table id: qual: %s, table name: %s", qdbid, m.TableName)
|
||||
}
|
||||
qtbl, err := mdsClient.Table(ctx, qtid)
|
||||
qtbl, err := controllerClient.Table(ctx, qtid)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getting table id: qtid: %s", qtid)
|
||||
}
|
||||
|
||||
m.Qtbl = qtbl
|
||||
m.Index = string(qtbl.Key())
|
||||
m.SchemaManager = mds.NewSchemaManager(dax.Address(m.MDSAddress), qdbid, m.log)
|
||||
m.SchemaManager = serverless.NewSchemaManager(dax.Address(m.ControllerAddress), qdbid, m.log)
|
||||
|
||||
m.NewImporterFn = func() pilosacore.Importer {
|
||||
return mds.NewImporter(mdsClient, qtbl.Qualifier(), &qtbl.Table)
|
||||
return serverless.NewImporter(controllerClient, qtbl.Qualifier(), &qtbl.Table)
|
||||
}
|
||||
} else {
|
||||
m.SchemaManager = m.client
|
||||
|
|
@ -1815,10 +1815,10 @@ func (m *Main) batchFromSchema(schema []Field) ([]Recordizer, pilosabatch.Record
|
|||
}
|
||||
|
||||
// The table name we use to look up in the index in the schema returned from
|
||||
// SchemaManager.Schema() differs depending on whether this is MDS supported
|
||||
// or not (i.e. whether it has a table qualifier).
|
||||
// SchemaManager.Schema() differs depending on whether this is Serverless
|
||||
// supported or not (i.e. whether it has a table qualifier).
|
||||
tblName := m.index.Name()
|
||||
if m.useMDS() {
|
||||
if m.useController() {
|
||||
tblName = string(m.Qtbl.Key())
|
||||
}
|
||||
|
||||
|
|
@ -1847,7 +1847,7 @@ func (m *Main) newBatch(fields []*pilosaclient.Field) (pilosabatch.RecordBatch,
|
|||
pilosabatch.OptUseShardTransactionalEndpoint(m.UseShardTransactionalEndpoint),
|
||||
}
|
||||
var importer pilosacore.Importer
|
||||
if m.useMDS() {
|
||||
if m.useController() {
|
||||
importer = m.NewImporterFn()
|
||||
} else {
|
||||
sapi := pilosaclient.NewSchemaAPI(m.client)
|
||||
|
|
@ -2157,7 +2157,7 @@ func (m *Main) validate() error {
|
|||
return errors.New("must set exactly one of --primary-key-field <fieldnames>, --id-field <fieldname>, --auto-generate")
|
||||
}
|
||||
|
||||
if m.useMDS() {
|
||||
if m.useController() {
|
||||
if m.OrganizationID == "" {
|
||||
return errors.New("must set an organization with --featurebase.org-id")
|
||||
} else if m.DatabaseID == "" {
|
||||
|
|
@ -2189,6 +2189,6 @@ func (m *Main) allowError(err error) bool {
|
|||
}
|
||||
}
|
||||
|
||||
func (m *Main) useMDS() bool {
|
||||
return m.MDSAddress != ""
|
||||
func (m *Main) useController() bool {
|
||||
return m.ControllerAddress != ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ import (
|
|||
batch "github.com/featurebasedb/featurebase/v3/batch"
|
||||
pilosaclient "github.com/featurebasedb/featurebase/v3/client"
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
mdsclient "github.com/featurebasedb/featurebase/v3/dax/mds/client"
|
||||
controllerclient "github.com/featurebasedb/featurebase/v3/dax/controller/client"
|
||||
"github.com/featurebasedb/featurebase/v3/idk/idktest"
|
||||
"github.com/featurebasedb/featurebase/v3/idk/mds"
|
||||
"github.com/featurebasedb/featurebase/v3/idk/serverless"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
"github.com/featurebasedb/featurebase/v3/pql"
|
||||
"github.com/golang-jwt/jwt"
|
||||
|
|
@ -44,8 +44,8 @@ func configureTestFlags(main *Main) {
|
|||
main.Stats = ""
|
||||
}
|
||||
|
||||
func configureTestFlagsMDS(main *Main, address dax.Address, qtbl *dax.QualifiedTable) {
|
||||
main.MDSAddress = address.String()
|
||||
func configureTestFlagsController(main *Main, address dax.Address, qtbl *dax.QualifiedTable) {
|
||||
main.ControllerAddress = address.String()
|
||||
main.Stats = ""
|
||||
main.Pprof = ""
|
||||
main.PackBools = ""
|
||||
|
|
@ -53,12 +53,12 @@ func configureTestFlagsMDS(main *Main, address dax.Address, qtbl *dax.QualifiedT
|
|||
main.DatabaseID = qtbl.Qualifier().DatabaseID
|
||||
main.TableName = qtbl.Name
|
||||
main.Qtbl = qtbl
|
||||
main.SchemaManager = mds.NewSchemaManager(address, qtbl.Qualifier(), logger.StderrLogger)
|
||||
main.SchemaManager = serverless.NewSchemaManager(address, qtbl.Qualifier(), logger.StderrLogger)
|
||||
main.Index = string(qtbl.Key())
|
||||
|
||||
mdsClient := mdsclient.New(dax.Address(address), logger.StderrLogger)
|
||||
controllerClient := controllerclient.New(dax.Address(address), logger.StderrLogger)
|
||||
main.NewImporterFn = func() pilosa.Importer {
|
||||
return mds.NewImporter(mdsClient, qtbl.QualifiedDatabaseID, &qtbl.Table)
|
||||
return serverless.NewImporter(controllerClient, qtbl.QualifiedDatabaseID, &qtbl.Table)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1744,19 +1744,19 @@ func TestBoolIngest(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestBatchTargetMDS(t *testing.T) {
|
||||
var mdsHost string
|
||||
if mds, ok := os.LookupEnv("IDK_TEST_MDS_HOST"); ok {
|
||||
mdsHost = mds
|
||||
func TestBatchTargetServerless(t *testing.T) {
|
||||
var controllerHost string
|
||||
if controller, ok := os.LookupEnv("IDK_TEST_CONTROLLER_HOST"); ok {
|
||||
controllerHost = controller
|
||||
} else {
|
||||
mdsHost = "dax:8080"
|
||||
controllerHost = "dax:8080"
|
||||
}
|
||||
|
||||
mdsAddress := dax.Address(mdsHost + "/" + dax.ServicePrefixMDS)
|
||||
controllerAddress := dax.Address(controllerHost + "/" + dax.ServicePrefixController)
|
||||
orgID := dax.OrganizationID("acme")
|
||||
dbID := dax.DatabaseID("db1")
|
||||
|
||||
mdsClient := mdsclient.New(mdsAddress, logger.StderrLogger)
|
||||
controllerClient := controllerclient.New(controllerAddress, logger.StderrLogger)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
|
|
@ -1772,7 +1772,7 @@ func TestBatchTargetMDS(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
mdsClient.CreateDatabase(ctx, qdb)
|
||||
controllerClient.CreateDatabase(ctx, qdb)
|
||||
|
||||
t.Run("FieldTypes", func(t *testing.T) {
|
||||
tests := []struct {
|
||||
|
|
@ -1850,7 +1850,7 @@ func TestBatchTargetMDS(t *testing.T) {
|
|||
{1, time.Now()},
|
||||
{2, time.Now()},
|
||||
},
|
||||
fieldOptions: dax.FieldOptions{TimeUnit: "s", Epoch: time.Unix(0, 0)}, // TODO w/o this, it used to silently fail (just logs in the mds svc). Eventually should probably have a default unit and not fail at all.
|
||||
fieldOptions: dax.FieldOptions{TimeUnit: "s", Epoch: time.Unix(0, 0)}, // TODO w/o this, it used to silently fail (just logs in the controller svc). Eventually should probably have a default unit and not fail at all.
|
||||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
|
|
@ -1881,14 +1881,14 @@ func TestBatchTargetMDS(t *testing.T) {
|
|||
tbl,
|
||||
)
|
||||
|
||||
// Create the table in MDS Schemar.
|
||||
if err := mdsClient.CreateTable(ctx, qtbl); err != nil {
|
||||
// Create the table in Controller Schemar.
|
||||
if err := controllerClient.CreateTable(ctx, qtbl); err != nil {
|
||||
t.Fatalf("creating table: %v", err)
|
||||
}
|
||||
|
||||
// qtblWithID is the same as qtbl above, but now MDS has
|
||||
// qtblWithID is the same as qtbl above, but now Controller has
|
||||
// assigned the table a unique ID.
|
||||
qtblWithID, err := mdsClient.Table(ctx, qtbl.QualifiedID())
|
||||
qtblWithID, err := controllerClient.Table(ctx, qtbl.QualifiedID())
|
||||
assert.NoError(t, err)
|
||||
|
||||
ts := newTestSource([]Field{
|
||||
|
|
@ -1897,7 +1897,7 @@ func TestBatchTargetMDS(t *testing.T) {
|
|||
}, test.in)
|
||||
|
||||
ingester := NewMain()
|
||||
configureTestFlagsMDS(ingester, mdsAddress, qtblWithID)
|
||||
configureTestFlagsController(ingester, controllerAddress, qtblWithID)
|
||||
|
||||
ingester.NewSource = func() (Source, error) { return ts, nil }
|
||||
ingester.BatchSize = 10
|
||||
|
|
|
|||
|
|
@ -1312,13 +1312,13 @@ func (f Fields) ContainsBool() bool {
|
|||
|
||||
// SchemaManager is meant to be an interface for managing schema information;
|
||||
// i.e. for interacting with a single source of truth for schema information,
|
||||
// like the MDS Schemar. But... it currently contains methods which are not
|
||||
// related to schema because the first goal was just to introduce an interface
|
||||
// in ingest.go for any methods being called on *m.client. We don't want a
|
||||
// FeatureBase client directly called from ingest, rather, we want to call these
|
||||
// interface methods and allow for different implementations (such as an MDS
|
||||
// implementation which uses the Schemar in MDS as opposed to a FeatureBase node
|
||||
// or cluster).
|
||||
// like the Serverless Schemar. But... it currently contains methods which are
|
||||
// not related to schema because the first goal was just to introduce an
|
||||
// interface in ingest.go for any methods being called on *m.client. We don't
|
||||
// want a FeatureBase client directly called from ingest, rather, we want to
|
||||
// call these interface methods and allow for different implementations (such as
|
||||
// a Serverless implementation which uses the Schemar in Serverless as opposed
|
||||
// to a FeatureBase node or cluster).
|
||||
type SchemaManager interface {
|
||||
StartTransaction(id string, timeout time.Duration, exclusive bool, requestTimeout time.Duration) (*pilosacore.Transaction, error)
|
||||
FinishTransaction(id string) (*pilosacore.Transaction, error)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package mds
|
||||
package serverless
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -8,7 +8,7 @@ import (
|
|||
featurebase "github.com/featurebasedb/featurebase/v3"
|
||||
featurebaseclient "github.com/featurebasedb/featurebase/v3/client"
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/mds/controller/partitioner"
|
||||
"github.com/featurebasedb/featurebase/v3/dax/controller/partitioner"
|
||||
"github.com/featurebasedb/featurebase/v3/roaring"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package mds
|
||||
package serverless
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -7,7 +7,7 @@ import (
|
|||
featurebase "github.com/featurebasedb/featurebase/v3"
|
||||
featurebase_client "github.com/featurebasedb/featurebase/v3/client"
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
mdsclient "github.com/featurebasedb/featurebase/v3/dax/mds/client"
|
||||
controllerclient "github.com/featurebasedb/featurebase/v3/dax/controller/client"
|
||||
"github.com/featurebasedb/featurebase/v3/errors"
|
||||
"github.com/featurebasedb/featurebase/v3/logger"
|
||||
)
|
||||
|
|
@ -17,14 +17,14 @@ import (
|
|||
|
||||
// schemaManager
|
||||
type schemaManager struct {
|
||||
client *mdsclient.Client
|
||||
client *controllerclient.Client
|
||||
qdbid dax.QualifiedDatabaseID
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
func NewSchemaManager(mdsAddress dax.Address, qdbid dax.QualifiedDatabaseID, logger logger.Logger) *schemaManager {
|
||||
func NewSchemaManager(controllerAddress dax.Address, qdbid dax.QualifiedDatabaseID, logger logger.Logger) *schemaManager {
|
||||
return &schemaManager{
|
||||
client: mdsclient.New(mdsAddress, logger),
|
||||
client: controllerclient.New(controllerAddress, logger),
|
||||
qdbid: qdbid,
|
||||
logger: logger,
|
||||
}
|
||||
|
|
@ -52,11 +52,11 @@ type Config struct {
|
|||
// Name a unique name for this node in the cluster.
|
||||
Name string `toml:"name"`
|
||||
|
||||
// MDSAddress is the location at which this node should register itself and
|
||||
// retrieve its instructions. For example, after registring, the MDS service
|
||||
// might tell this node that it is responsible for specific shards for a
|
||||
// particular index.
|
||||
MDSAddress string `toml:"mds-address"`
|
||||
// ControllerAddress is the location at which this node should register
|
||||
// itself and retrieve its instructions. For example, after registring, the
|
||||
// Controller service might tell this node that it is responsible for
|
||||
// specific shards for a particular index.
|
||||
ControllerAddress string `toml:"controller-address"`
|
||||
|
||||
// WriteloggerDir is the location at which this node should
|
||||
// read/write change logs. Typically a network mounted filesystem
|
||||
|
|
@ -210,7 +210,7 @@ type Config struct {
|
|||
} `toml:"sql"`
|
||||
|
||||
// CheckInTimeout is the amount of time between compute node check-ins to
|
||||
// MDS.
|
||||
// Controller.
|
||||
CheckInInterval time.Duration `toml:"check-in-interval"`
|
||||
|
||||
// Storage.Backend determines which Tx implementation the holder/Index will
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ func OptCommandConfig(config *Config) CommandOption {
|
|||
c.Config.Etcd = config.Etcd
|
||||
c.Config.Auth = config.Auth
|
||||
c.Config.TLS = config.TLS
|
||||
c.Config.MDSAddress = config.MDSAddress
|
||||
c.Config.ControllerAddress = config.ControllerAddress
|
||||
c.Config.SQL.EndpointEnabled = config.SQL.EndpointEnabled
|
||||
return nil
|
||||
}
|
||||
|
|
@ -280,7 +280,7 @@ func (m *Command) StartNoServe(addr dax.Address) (err error) {
|
|||
}
|
||||
|
||||
// Start the "check-in" background process which periodically checks in with
|
||||
// MDS.
|
||||
// the Controller.
|
||||
go m.checkIn(addr)
|
||||
|
||||
return nil
|
||||
|
|
@ -303,7 +303,7 @@ func (m *Command) checkIn(addr dax.Address) {
|
|||
m.logger.Debugf("node check-in in last %s, address: %s", interval, m.Config.Advertise)
|
||||
|
||||
if m.Registrar == nil {
|
||||
m.logger.Printf("no MDS implementation with which to check-in on node: %s", m.Config.Advertise)
|
||||
m.logger.Printf("no Controller implementation with which to check-in on node: %s", m.Config.Advertise)
|
||||
}
|
||||
|
||||
node := &dax.Node{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue