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:
Travis Turner 2023-01-30 16:54:12 -06:00 committed by GitHub
parent b12c90fdd1
commit 20429bb9dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 606 additions and 1370 deletions

8
api.go
View file

@ -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()

View file

@ -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.")

View file

@ -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.")

View file

@ -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 ###############################

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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"

View file

@ -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)

View file

@ -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"
)

View file

@ -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"

View file

@ -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,
}

View file

@ -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:"-"`
}

View file

@ -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")
}

View file

@ -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{

View file

@ -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"
)

View file

@ -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

View file

@ -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"
)

View file

@ -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

View file

@ -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"
)

View file

@ -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"

View 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)
}

View file

@ -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

View file

@ -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"

View file

@ -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"`

View file

@ -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"

View file

@ -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
}
}

View file

@ -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

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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

View file

@ -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:"-"`
}

View file

@ -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]

View file

@ -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{}

View file

@ -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
}

View file

@ -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 {

View file

@ -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,

View file

@ -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.

View file

@ -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"))
}

View file

@ -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
}
//////////////////////////////////////////

View file

@ -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"))
})
}

View file

@ -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"
)

View file

@ -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
}

View file

@ -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)

View file

@ -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

View file

@ -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 != ""
}

View file

@ -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

View file

@ -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)

View file

@ -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"
)

View file

@ -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,
}

View file

@ -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

View file

@ -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{