com.mysql.cj.jdbc.ha.ReplicationConnectionGroup Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mysql-connector-j Show documentation
Show all versions of mysql-connector-j Show documentation
JDBC Type 4 driver for MySQL.
The newest version!
/*
* Copyright (c) 2013, 2024, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by
* the Free Software Foundation.
*
* This program is designed to work with certain software that is licensed under separate terms, as designated in a particular file or component or in
* included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the
* separately licensed software that they have either included with the program or referenced in the documentation.
*
* Without limiting anything contained in the foregoing, this file, which is part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
* version 1.0, a copy of which can be found at http://oss.oracle.com/licenses/universal-foss-exception.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.mysql.cj.jdbc.ha;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Group of connection objects that can be configured as a group. This is used for promotion/demotion of replicas and sources in a replication configuration,
* and for exposing metrics around replication-aware connections.
*/
public class ReplicationConnectionGroup {
private String groupName;
private long connections = 0;
private long replicasAdded = 0;
private long replicasRemoved = 0;
private long replicasPromoted = 0;
private long activeConnections = 0;
private HashMap replicationConnections = new HashMap<>();
private Set replicaHostList = new CopyOnWriteArraySet<>();
private boolean isInitialized = false;
private Set sourceHostList = new CopyOnWriteArraySet<>();
ReplicationConnectionGroup(String groupName) {
this.groupName = groupName;
}
public long getConnectionCount() {
return this.connections;
}
public long registerReplicationConnection(ReplicationConnection conn, List localSourceList, List localReplicaList) {
long currentConnectionId;
synchronized (this) {
if (!this.isInitialized) {
if (localSourceList != null) {
this.sourceHostList.addAll(localSourceList);
}
if (localReplicaList != null) {
this.replicaHostList.addAll(localReplicaList);
}
this.isInitialized = true;
}
currentConnectionId = ++this.connections;
this.replicationConnections.put(Long.valueOf(currentConnectionId), conn);
}
this.activeConnections++;
return currentConnectionId;
}
public String getGroupName() {
return this.groupName;
}
public Collection getSourceHosts() {
return this.sourceHostList;
}
public Collection getReplicaHosts() {
return this.replicaHostList;
}
/**
* Adds a host to the replicas hosts list.
*
* We can safely assume that if this host was added to the replicas list, then it must be added to each one of the replication connections from this group
* as well.
* Unnecessary calls to {@link ReplicationConnection#addReplicaHost(String)} could result in undesirable locking issues, assuming that this method is
* synchronized by nature.
*
* This is a no-op if the group already has this host in a replica role.
*
* @param hostPortPair
* "host:port"
* @throws SQLException
* if an error occurs
*/
public void addReplicaHost(String hostPortPair) throws SQLException {
// only add if it's not already a replica host
if (this.replicaHostList.add(hostPortPair)) {
this.replicasAdded++;
// add the replica to all connections:
for (ReplicationConnection c : this.replicationConnections.values()) {
c.addReplicaHost(hostPortPair);
}
}
}
public void handleCloseConnection(ReplicationConnection conn) {
this.replicationConnections.remove(conn.getConnectionGroupId());
this.activeConnections--;
}
/**
* Removes a host from the replicas hosts list.
*
* We can safely assume that if this host was removed from the replicas list, then it must be removed from each one of the replication connections from this
* group as well.
* Unnecessary calls to {@link ReplicationConnection#removeReplica(String, boolean)} could result in undesirable locking issues, assuming that this method
* is synchronized by nature.
*
* This is a no-op if the group doesn't have this host in a replica role.
*
* @param hostPortPair
* "host:port"
* @param closeGently
* remove host when it's not in use
* @throws SQLException
* if an error occurs
*/
public void removeReplicaHost(String hostPortPair, boolean closeGently) throws SQLException {
if (this.replicaHostList.remove(hostPortPair)) {
this.replicasRemoved++;
// remove the replica from all connections:
for (ReplicationConnection c : this.replicationConnections.values()) {
c.removeReplica(hostPortPair, closeGently);
}
}
}
/**
* Promotes a replica host to source.
*
* We can safely assume that if this host was removed from the replicas list or added to the sources list, then the same host promotion must happen in each
* one of the replication connections from this group as well.
*
* Unnecessary calls to {@link ReplicationConnection#promoteReplicaToSource(String)} could result in undesirable locking issues, assuming that this method
* is synchronized by nature.
*
* This is a no-op if the group already has this host in a source role and not in replica role.
*
* @param hostPortPair
* "host:port"
* @throws SQLException
* if an error occurs
*/
public void promoteReplicaToSource(String hostPortPair) throws SQLException {
// remove host from replicas AND add host to sources, note that both operands need to be evaluated.
if (this.replicaHostList.remove(hostPortPair) | this.sourceHostList.add(hostPortPair)) {
this.replicasPromoted++;
for (ReplicationConnection c : this.replicationConnections.values()) {
c.promoteReplicaToSource(hostPortPair);
}
}
}
/**
* Removes a host from the sources hosts list.
*
* @param hostPortPair
* host:port
* @throws SQLException
* if an error occurs
*/
public void removeSourceHost(String hostPortPair) throws SQLException {
this.removeSourceHost(hostPortPair, true);
}
/**
* Removes a host from the sources hosts list.
*
* We can safely assume that if this host was removed from the sources list, then it must be removed from each one of the replication connections from this
* group as well.
* Unnecessary calls to {@link ReplicationConnection#removeSourceHost(String, boolean)} could result in undesirable locking issues, assuming that this
* method is synchronized by nature.
*
* This is a no-op if the group doesn't have this host in a source role.
*
* @param hostPortPair
* "host:port"
* @param closeGently
* remove host when it's not in use
* @throws SQLException
* if an error occurs
*/
public void removeSourceHost(String hostPortPair, boolean closeGently) throws SQLException {
if (this.sourceHostList.remove(hostPortPair)) {
// remove the source from all connections:
for (ReplicationConnection c : this.replicationConnections.values()) {
c.removeSourceHost(hostPortPair, closeGently);
}
}
}
public int getConnectionCountWithHostAsReplica(String hostPortPair) {
int matched = 0;
for (ReplicationConnection c : this.replicationConnections.values()) {
if (c.isHostReplica(hostPortPair)) {
matched++;
}
}
return matched;
}
public int getConnectionCountWithHostAsSource(String hostPortPair) {
int matched = 0;
for (ReplicationConnection c : this.replicationConnections.values()) {
if (c.isHostSource(hostPortPair)) {
matched++;
}
}
return matched;
}
public long getNumberOfReplicasAdded() {
return this.replicasAdded;
}
public long getNumberOfReplicasRemoved() {
return this.replicasRemoved;
}
public long getNumberOfReplicaPromotions() {
return this.replicasPromoted;
}
public long getTotalConnectionCount() {
return this.connections;
}
public long getActiveConnectionCount() {
return this.activeConnections;
}
@Override
public String toString() {
return "ReplicationConnectionGroup[groupName=" + this.groupName + ",sourceHostList=" + this.sourceHostList + ",replicaHostList=" + this.replicaHostList
+ "]";
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy