Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 10
Multi-cluster support: MySQL and PostgreSQL simultaneously#75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -60,6 +60,32 @@ const ( | ||
| var instanceReadChan = make(chan bool, backendDBConcurrency) | ||
| var instanceWriteChan = make(chan bool, backendDBConcurrency) | ||
| // detectProviderType determines whether an instance is MySQL or PostgreSQL. | ||
| // It checks (in order): | ||
| // 1. The orchestrator backend DB for a previously stored provider_type | ||
| // 2. Port-based heuristic (5432 -> postgresql) | ||
| // 3. The global config.Config.ProviderType as fallback (backward compat) | ||
| func detectProviderType(instanceKey *InstanceKey) string { | ||
| // Check if we already know this instance's provider type from the backend DB | ||
| query := `SELECT provider_type FROM database_instance WHERE hostname = ? AND port = ?` | ||
| var providerType string | ||
| err := db.QueryOrchestrator(query, sqlutils.Args(instanceKey.Hostname, instanceKey.Port), func(m sqlutils.RowMap) error { | ||
| providerType = m.GetString("provider_type") | ||
| return nil | ||
| }) | ||
| if err == nil && providerType != "" { | ||
| return providerType | ||
| } | ||
| // Port-based heuristic for new instances | ||
| if instanceKey.Port == 5432 { | ||
| return "postgresql" | ||
| } | ||
| // Fall back to global config (backward compatibility) | ||
| return config.Config.ProviderType | ||
| } | ||
Comment on lines
+68
to
+87
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The funcdetectProviderType(instanceKey*InstanceKey) string {
cacheKey:=instanceKey.StringCode()
ifval, found:=providerTypeCache.Get(cacheKey); found {
returnval.(string)
}
varproviderTypestring// Check if we already know this instance's provider type from the backend DBquery:=`SELECT provider_type FROM database_instance WHERE hostname = ? AND port = ?`err:=db.QueryOrchestrator(query, sqlutils.Args(instanceKey.Hostname, instanceKey.Port), func(m sqlutils.RowMap) error {
providerType=m.GetString("provider_type")
returnnil
})
iferr==nil&&providerType!="" {
// Found in DB
} elseifinstanceKey.Port==5432 {
providerType="postgresql"
} else {
providerType=config.Config.ProviderType
}
providerTypeCache.Set(cacheKey, providerType, cache.DefaultExpiration)
returnproviderType
} | ||
| // InstancesByCountReplicas is a sortable type for Instance | ||
| type InstancesByCountReplicas [](*Instance) | ||
| @@ -226,7 +252,8 @@ func logReadTopologyInstanceError(instanceKey *InstanceKey, hint string, err err | ||
| // server and writes the result synchronously to the orchestrator | ||
| // backend. | ||
| func ReadTopologyInstance(instanceKey *InstanceKey) (*Instance, error) { | ||
| if config.Config.ProviderType == "postgresql" { | ||
| providerType := detectProviderType(instanceKey) | ||
| if providerType == "postgresql" { | ||
| inst, err := ReadPostgreSQLTopologyInstance(instanceKey) | ||
| if err != nil { | ||
| // Mark the instance as checked-but-not-seen so analysis detects it as dead | ||
| @@ -360,7 +387,7 @@ func expectReplicationThreadsState(instance *Instance, instanceKey *InstanceKey, | ||
| // - timing information can be collected for the stages performed. | ||
| func ReadTopologyInstanceBufferable(instanceKey *InstanceKey, bufferWrites bool, latency *stopwatch.NamedStopwatch) (inst *Instance, skipped bool, err error) { | ||
| // PostgreSQL path: delegate to PG-specific discovery and skip MySQL logic entirely | ||
| if config.Config.ProviderType == "postgresql" { | ||
| if detectProviderType(instanceKey) == "postgresql" { | ||
| if latency != nil { | ||
| latency.Start("instance") | ||
| } | ||
| @@ -1222,7 +1249,7 @@ func ReadReplicationGroupPrimary(instance *Instance) (err error) { | ||
| func ReadInstanceClusterAttributes(instance *Instance) (err error) { | ||
| // PostgreSQL provider sets ClusterName directly during discovery. | ||
| // Skip the master-lookup logic which is MySQL-specific. | ||
| if config.Config.ProviderType == "postgresql" { | ||
| if instance.ProviderType == "postgresql" || detectProviderType(&instance.Key) == "postgresql" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Calling ifinstance.ProviderType=="" {
instance.ProviderType=detectProviderType(&instance.Key)
}
ifinstance.ProviderType=="postgresql" { | ||
| return nil | ||
| } | ||
| var masterOrGroupPrimaryInstanceKey InstanceKey | ||
| @@ -1462,6 +1489,10 @@ func readInstanceRow(m sqlutils.RowMap) *Instance { | ||
| Port: m.GetInt("replication_group_primary_port")} | ||
| _ = instance.ReplicationGroupMembers.ReadJson(m.GetString("replication_group_members")) | ||
| //instance.ReplicationGroup = m.GetString("replication_group_") | ||
| instance.ProviderType = m.GetString("provider_type") | ||
| if instance.ProviderType == "" { | ||
| instance.ProviderType = "mysql" | ||
| } | ||
| // problems | ||
| if !instance.IsLastCheckValid { | ||
| @@ -2780,6 +2811,7 @@ func mkInsertOdkuForInstances(instances []*Instance, instanceWasActuallyFound bo | ||
| "replication_group_members", | ||
| "replication_group_primary_host", | ||
| "replication_group_primary_port", | ||
| "provider_type", | ||
| } | ||
| var values = make([]string, len(columns)) | ||
| @@ -2873,6 +2905,11 @@ func mkInsertOdkuForInstances(instances []*Instance, instanceWasActuallyFound bo | ||
| args = append(args, instance.ReplicationGroupMembers.ToJSONString()) | ||
| args = append(args, instance.ReplicationGroupPrimaryInstanceKey.Hostname) | ||
| args = append(args, instance.ReplicationGroupPrimaryInstanceKey.Port) | ||
| providerType := instance.ProviderType | ||
| if providerType == "" { | ||
| providerType = "mysql" | ||
| } | ||
| args = append(args, providerType) | ||
| } | ||
| sql, err := mkInsertOdku("database_instance", columns, values, len(instances), insertIgnore) | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid frequent and redundant database queries to the orchestrator backend during the discovery process, consider introducing a cache for the instance provider type. This is especially important as
detectProviderTypeis called multiple times per discovery cycle for each instance.