Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@
<enforcer.version>3.0.0-M3</enforcer.version>
<commons-io.version>2.17.0</commons-io.version>
<burningwave.mockdns.version>0.25.4</burningwave.mockdns.version>
<dnsjava.version>3.5.1</dnsjava.version>
<clover-maven-plugin.version>4.4.1</clover-maven-plugin.version>
<sonar-maven-plugin.version>3.7.0.1746</sonar-maven-plugin.version>

Expand Down Expand Up @@ -774,6 +775,11 @@
<artifactId>tools</artifactId>
<version>${burningwave.mockdns.version}</version>
</dependency>
<dependency>
<groupId>dnsjava</groupId>
<artifactId>dnsjava</artifactId>
<version>${dnsjava.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1396,6 +1396,11 @@ and [SASL authentication for ZooKeeper](https://cwiki.apache.org/confluence/disp
you want to randomize that.
Default: false

* *zookeeper.hostProvider.dnsSrvRefreshIntervalSeconds* :
**New in 3.10.0:**
Specifies the refresh interval in seconds for DNS SRV record lookups when using DnsSrvHostProvider.
A value of 0 disables periodic refresh.
Default: 60 seconds

<a name="C+Binding"></a>

Expand Down
4 changes: 4 additions & 0 deletions zookeeper-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@
<artifactId>commons-io</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>dnsjava</groupId>
<artifactId>dnsjava</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.apache.zookeeper.client.Chroot;
import org.apache.zookeeper.client.ConnectStringParser;
import org.apache.zookeeper.client.HostProvider;
import org.apache.zookeeper.client.HostProviderFactory;
import org.apache.zookeeper.client.StaticHostProvider;
import org.apache.zookeeper.client.ZKClientConfig;
import org.apache.zookeeper.client.ZooKeeperBuilder;
Expand Down Expand Up @@ -1140,10 +1141,9 @@ public ZooKeeper(ZooKeeperOptions options) throws IOException {
if (options.getHostProvider() != null) {
hostProvider = options.getHostProvider().apply(connectStringParser.getServerAddresses());
} else {
hostProvider = new StaticHostProvider(connectStringParser.getServerAddresses(), clientConfig);
hostProvider = HostProviderFactory.create(connectStringParser, clientConfig);
}
this.hostProvider = hostProvider;

chroot = Chroot.ofNullable(connectStringParser.getChrootPath());
cnxn = createConnection(
hostProvider,
Expand Down Expand Up @@ -1329,6 +1329,10 @@ public synchronized void close() throws InterruptedException {
LOG.debug("Ignoring unexpected exception during close", e);
}

if (hostProvider != null) {
hostProvider.close();
}

LOG.info("Session: 0x{} closed", Long.toHexString(getSessionId()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.List;
import org.apache.zookeeper.common.NetUtils;
import org.apache.zookeeper.common.PathUtils;
import org.apache.zookeeper.common.StringUtils;

/**
* A parser for ZooKeeper Client connect strings.
Expand All @@ -38,38 +39,88 @@
public final class ConnectStringParser {

private static final int DEFAULT_PORT = 2181;
private static final String DNS_SRV_PREFIX = "dns-srv://";

private final String chrootPath;
public enum ConnectionType {
DNS_SRV,
HOST_PORT
}

private String chrootPath;
private final ArrayList<InetSocketAddress> serverAddresses = new ArrayList<>();
private final ConnectionType connectionType;
private final String connectString;

/**
* Parse host and port by splitting client connectString
* with support for IPv6 literals
* @throws IllegalArgumentException
* for an invalid chroot path.
* Constructs a ConnectStringParser with given connect string.
*
* <p>Supports two connection string formats:</p>
* <ul>
* <li><strong>Host:Port format:</strong> "host1:2181,host2:2181/chroot"</li>
* <li><strong>DNS SRV format:</strong> "dns-srv://service.domain.com/chroot"</li>
* </ul>
*
* @param connectString the connect string to parse
* @throws IllegalArgumentException if connectString is null/empty or contains invalid chroot path
*/
public ConnectStringParser(String connectString) {
public ConnectStringParser(final String connectString) {
if (StringUtils.isBlank(connectString)) {
throw new IllegalArgumentException("Connect string cannot be null or empty");
}

if (connectString.startsWith(DNS_SRV_PREFIX)) {
connectionType = ConnectionType.DNS_SRV;
parseDnsSrvFormat(connectString);
} else {
connectionType = ConnectionType.HOST_PORT;
parseHostPortFormat(connectString);
}
this.connectString = connectString;
}

public String getChrootPath() {
return chrootPath;
}

public ArrayList<InetSocketAddress> getServerAddresses() {
return serverAddresses;
}

public ConnectionType getConnectionType() {
return connectionType;
}

public String getConnectString() {
return connectString;
}

private String[] parseConnectString(final String connectString) {
String serverPart = connectString;
String chrootPath = null;

// parse out chroot, if any
int off = connectString.indexOf('/');
final int off = connectString.indexOf('/');
if (off >= 0) {
String chrootPath = connectString.substring(off);
chrootPath = connectString.substring(off);
// ignore "/" chroot spec, same as null
if (chrootPath.length() == 1) {
this.chrootPath = null;
chrootPath = null;
} else {
PathUtils.validatePath(chrootPath);
this.chrootPath = chrootPath;
}
connectString = connectString.substring(0, off);
} else {
this.chrootPath = null;
serverPart = connectString.substring(0, off);
}
return new String[]{serverPart, chrootPath};
}

private void parseHostPortFormat(final String connectString) {
final String[] parts = parseConnectString(connectString);
chrootPath = parts[1];

List<String> hostsList = split(connectString, ",");
final List<String> hostsList = split(parts[0], ",");
for (String host : hostsList) {
int port = DEFAULT_PORT;
String[] hostAndPort = NetUtils.getIPV6HostAndPort(host);
final String[] hostAndPort = NetUtils.getIPV6HostAndPort(host);
if (hostAndPort.length != 0) {
host = hostAndPort[0];
if (hostAndPort.length == 2) {
Expand All @@ -89,12 +140,11 @@ public ConnectStringParser(String connectString) {
}
}

public String getChrootPath() {
return chrootPath;
private void parseDnsSrvFormat(final String connectString) {
final String[] parts = parseConnectString(connectString.substring(DNS_SRV_PREFIX.length()));
chrootPath = parts[1];
// The DNS service name is stored as a placeholder address
// The actual resolution will be handled by DnsSrvHostProvider
serverAddresses.add(InetSocketAddress.createUnresolved(parts[0], DEFAULT_PORT));
}

public ArrayList<InetSocketAddress> getServerAddresses() {
return serverAddresses;
}

}
Loading
Loading