mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
* Database isolation: Balancer
Remove naive Balancer
remove debugging lines
Thread dax.Transaction through Controller
Change role to roleType
Swap out Balancer interface with new one
Standardize InvalidTransaction error
Add some interface comments
* Remove type.Worker; replace with type.Address
* Remove database validate from Queryer
This is already being handled in the `CreateTable()` method. Prior
to doing that validation, we were getting a panic, but that's no longer
the case.
* Remove dax.TableQualifier; replace with dax.QualifiedDatabaseID
* Update IDK test to create database
(cherry picked from commit d971cfc269)
179 lines
5.5 KiB
Go
179 lines
5.5 KiB
Go
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.
|
|
type Directive struct {
|
|
Address Address `json:"address"`
|
|
|
|
// Method describes how the compute node should handle the Directive. See
|
|
// the different constants of type DirectiveMethod for how this value is
|
|
// handled.
|
|
Method DirectiveMethod `json:"method"`
|
|
|
|
Tables []*QualifiedTable `json:"schema"`
|
|
|
|
ComputeRoles []ComputeRole `json:"compute-roles"`
|
|
TranslateRoles []TranslateRole `json:"translate-roles"`
|
|
|
|
Version uint64 `json:"version"`
|
|
}
|
|
|
|
type DirectiveVersion interface {
|
|
Increment(tx Transaction, delta uint64) (uint64, error)
|
|
}
|
|
|
|
// DirectiveMethod is used to tell the compute node how it should handle the
|
|
// Directive.
|
|
type DirectiveMethod string
|
|
|
|
const (
|
|
// DirectiveMethodDiff tells the compute node to diff the Directive with its
|
|
// local, cached Directive and only apply the differences.
|
|
DirectiveMethodDiff DirectiveMethod = "diff"
|
|
|
|
// DirectiveMethodReset tells the compute node to delete all of its existing
|
|
// data before applying the directive.
|
|
DirectiveMethodReset DirectiveMethod = "reset"
|
|
|
|
// DirectiveMethodSnapshot tells the compute node that the incoming
|
|
// Directive should only contain data version updates related to a snapshot
|
|
// request.
|
|
DirectiveMethodSnapshot DirectiveMethod = "snapshot"
|
|
)
|
|
|
|
// Table returns the ID'd table from the Directive's Tables list. If it's not
|
|
// found, it returns nil and a non-nil error. A nil error guarantees that the
|
|
// returned table is non-nil.
|
|
func (d *Directive) Table(qtid QualifiedTableID) (*QualifiedTable, error) {
|
|
for _, qtbl := range d.Tables {
|
|
// We can't do qtbl.QualifiedID() == qtid because the value of qtid.Name
|
|
// is empty and causes the equality check to fail. Hence the .Equals()
|
|
// method.
|
|
if qtbl.QualifiedID().Equals(qtid) {
|
|
return qtbl, nil
|
|
}
|
|
}
|
|
return nil, NewErrTableIDDoesNotExist(qtid)
|
|
}
|
|
|
|
// ComputeShards returns the list of shards, for the given table, for which this
|
|
// compute node is responsible. It assumes that the Directive does not contain
|
|
// more than one ComputeRole for the same table; in that case, we would need to
|
|
// return the union of Shards.
|
|
func (d *Directive) ComputeShards(tbl TableKey) ShardNums {
|
|
if d == nil || d.ComputeRoles == nil {
|
|
return nil
|
|
}
|
|
|
|
for _, cr := range d.ComputeRoles {
|
|
if cr.TableKey == tbl {
|
|
return cr.Shards
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ComputeShardsMap returns a map of table to shards. It assumes that the
|
|
// Directive does not contain more than one ComputeRole for the same table; in
|
|
// that case, we would need to return the union of Shards.
|
|
func (d *Directive) ComputeShardsMap() map[TableKey]ShardNums {
|
|
m := make(map[TableKey]ShardNums)
|
|
if d == nil || d.ComputeRoles == nil {
|
|
return m
|
|
}
|
|
|
|
for _, cr := range d.ComputeRoles {
|
|
m[cr.TableKey] = cr.Shards
|
|
}
|
|
|
|
return m
|
|
}
|
|
|
|
// TranslatePartitions returns the list of partitions, for the given table, for
|
|
// which this translate node is responsible. It assumes that the Directive does
|
|
// not contain more than one TranslateRole for the same table; in that case, we
|
|
// would need to return the union of Shards.
|
|
func (d *Directive) TranslatePartitions(tbl TableKey) PartitionNums {
|
|
if d == nil || d.TranslateRoles == nil {
|
|
return PartitionNums{}
|
|
}
|
|
|
|
for _, tr := range d.TranslateRoles {
|
|
if tr.TableKey == tbl {
|
|
return tr.Partitions
|
|
}
|
|
}
|
|
return PartitionNums{}
|
|
}
|
|
|
|
// TranslatePartitionsMap returns a map of table to partitions. It assumes that
|
|
// the Directive does not contain more than one TranslateRole for the same
|
|
// table; in that case, we would need to return the union of Partitions.
|
|
func (d *Directive) TranslatePartitionsMap() map[TableKey]PartitionNums {
|
|
m := make(map[TableKey]PartitionNums)
|
|
if d == nil || d.TranslateRoles == nil {
|
|
return m
|
|
}
|
|
|
|
for _, tr := range d.TranslateRoles {
|
|
// Since we added FieldVersions to the TranslateRole, it's possible for
|
|
// a TranslateRole to have an empty Partitions list. In that case, we
|
|
// want to exclude that from the map.
|
|
if len(tr.Partitions) == 0 {
|
|
continue
|
|
}
|
|
m[tr.TableKey] = tr.Partitions
|
|
}
|
|
|
|
return m
|
|
}
|
|
|
|
// TranslateFieldsMap returns a map of table to fields. It assumes that
|
|
// the Directive does not contain more than one TranslateRole for the same
|
|
// table; in that case, we would need to return the union of FieldValues.
|
|
func (d *Directive) TranslateFieldsMap() map[TableKey][]FieldName {
|
|
m := make(map[TableKey][]FieldName)
|
|
if d == nil || d.TranslateRoles == nil {
|
|
return m
|
|
}
|
|
|
|
for _, tr := range d.TranslateRoles {
|
|
if len(tr.Fields) == 0 {
|
|
continue
|
|
}
|
|
m[tr.TableKey] = tr.Fields
|
|
}
|
|
|
|
return m
|
|
}
|
|
|
|
// IsEmpty tells whether a directive is assigning actual responsibilty
|
|
// to a node or not. If the directive does not assign responsibility
|
|
// for any shard or partition then it is considered empty. This is
|
|
// used to determine whether we can ignore an error received from
|
|
// applying this directive (an empty directive is often sent to a node
|
|
// which is already down).
|
|
func (d *Directive) IsEmpty() bool {
|
|
for _, role := range d.ComputeRoles {
|
|
if len(role.Shards) > 0 {
|
|
return false
|
|
}
|
|
}
|
|
|
|
for _, role := range d.TranslateRoles {
|
|
if len(role.Partitions) > 0 {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Directives is a sortable slice of Directive.
|
|
type Directives []*Directive
|
|
|
|
func (d Directives) Len() int { return len(d) }
|
|
func (d Directives) Less(i, j int) bool { return d[i].Version < d[j].Version }
|
|
func (d Directives) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|