use of com.mysql.cj.xdevapi.Client in project aws-mysql-jdbc by awslabs.
the class SessionTest method pooledSessionFailoverByPrioritiesAndPooling.
@Test
public void pooledSessionFailoverByPrioritiesAndPooling() {
UnreliableSocketFactory.flushAllStaticData();
final String testUriPattern = "mysqlx://%s:%s@[%s]/%s?" + PropertyKey.xdevapiConnectTimeout.getKeyName() + "=100&" + PropertyKey.socketFactory.getKeyName() + "=" + UnreliableSocketFactory.class.getName();
String testHosts = IntStream.range(1, 6).mapToObj(i -> "host" + i).peek(h -> UnreliableSocketFactory.mapHost(h, getTestHost())).map(h -> "(address=" + h + ":" + getTestPort() + ",priority=%d)").collect(Collectors.joining(","));
String testUriPatternPriorities = String.format(testUriPattern, getTestUser() == null ? "" : getTestUser(), getTestPassword() == null ? "" : getTestPassword(), testHosts, getTestDatabase());
String testUri = String.format(testUriPatternPriorities, 60, 80, 100, 20, 40);
int[] hostsOrder = new int[] { 3, 2, 1, 5, 4 };
final ClientFactory cf = new ClientFactory();
Client client = cf.getClient(testUri, "{\"pooling\" : {\"enabled\" : true, \"maxSize\" : 10} }");
for (int i = 0; i < hostsOrder.length; i++) {
int h = hostsOrder[i];
Session testSession = client.getSession();
assertTrue(UnreliableSocketFactory.isConnected());
// Pool this connection.
testSession.close();
String lastHost = UnreliableSocketFactory.getHostFromLastConnection();
assertEquals(UnreliableSocketFactory.getHostConnectedStatus("host" + h), lastHost);
List<String> connectionAttempts = UnreliableSocketFactory.getHostsFromAllConnections();
assertEquals(i == 0 ? 1 : 2, connectionAttempts.size());
for (int a = 0; a < connectionAttempts.size() - 1; a++) {
assertEquals(UnreliableSocketFactory.getHostFailedStatus("host" + hostsOrder[i - 1 + a]), connectionAttempts.get(a));
}
UnreliableSocketFactory.downHost("host" + h);
UnreliableSocketFactory.flushConnectionAttempts();
}
// None of the hosts is available by now.
assertThrows(CJCommunicationsException.class, "Unable to connect to any of the target hosts\\.", () -> {
client.getSession();
return null;
});
// Final connection tried the last known to be good host (host4) and then the remaining hosts by their priority
List<String> connectionAttempts = UnreliableSocketFactory.getHostsFromAllConnections();
for (int i = 0; i < hostsOrder.length; i++) {
assertEquals(UnreliableSocketFactory.getHostFailedStatus("host" + hostsOrder[(i + 4) % 5]), connectionAttempts.get(i));
}
UnreliableSocketFactory.dontDownHost("host" + hostsOrder[1]);
UnreliableSocketFactory.flushConnectionAttempts();
Session testSession = client.getSession();
assertTrue(UnreliableSocketFactory.isConnected());
testSession.close();
connectionAttempts = UnreliableSocketFactory.getHostsFromAllConnections();
assertEquals(2, connectionAttempts.size());
assertEquals(UnreliableSocketFactory.getHostFailedStatus("host" + hostsOrder[0]), connectionAttempts.get(0));
assertEquals(UnreliableSocketFactory.getHostConnectedStatus("host" + hostsOrder[1]), connectionAttempts.get(1));
UnreliableSocketFactory.flushConnectionAttempts();
// Pick previous connection from the pool. Doesn't count as new connections.
Session testSession1 = client.getSession();
assertEquals(0, UnreliableSocketFactory.getHostsFromAllConnections().size());
// Create a new connection.
Session testSession2 = client.getSession();
assertTrue(UnreliableSocketFactory.isConnected());
testSession1.close();
testSession2.close();
connectionAttempts = UnreliableSocketFactory.getHostsFromAllConnections();
assertEquals(1, connectionAttempts.size());
assertEquals(UnreliableSocketFactory.getHostConnectedStatus("host" + hostsOrder[1]), connectionAttempts.get(0));
client.close();
}
use of com.mysql.cj.xdevapi.Client in project aws-mysql-jdbc by awslabs.
the class SessionTest method testPreparedStatementsPooledConnections.
@Test
public void testPreparedStatementsPooledConnections() {
assumeTrue(mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.14")), "MySQL 8.0.14+ is required to run this test.");
Properties props = new Properties();
props.setProperty(ClientProperty.POOLING_ENABLED.getKeyName(), "true");
props.setProperty(ClientProperty.POOLING_MAX_SIZE.getKeyName(), "1");
try {
this.schema.createCollection("testPrepStmtPooling", true).add("{\"_id\":\"1\"}").execute();
ClientFactory cf = new ClientFactory();
Client testClient = cf.getClient(this.baseUrl, props);
Session testSession = testClient.getSession();
int sessionThreadId = getThreadId(testSession);
assertPreparedStatementsCount(sessionThreadId, 0, 1);
FindStatement testFind = testSession.getDefaultSchema().getCollection("testPrepStmtPooling").find();
// 1st execute -> don't prepare.
testFind.execute();
assertPreparedStatementsCountsAndId(testSession, 0, testFind, 0, -1);
assertPreparedStatementsStatusCounts(testSession, 0, 0, 0);
// 2nd execute -> prepare + execute.
testFind.execute();
assertPreparedStatementsCountsAndId(testSession, 1, testFind, 1, 1);
assertPreparedStatementsStatusCounts(testSession, 1, 1, 0);
assertPreparedStatementsCount(sessionThreadId, 1, 1);
// Prepared statements won't live past closing the session, or returning it to the pool.
testSession.close();
assertPreparedStatementsCount(sessionThreadId, 0, 10);
testSession = testClient.getSession();
sessionThreadId = getThreadId(testSession);
assertPreparedStatementsCount(sessionThreadId, 0, 1);
// The underlying connection object in testFind is the same as the one returned from the pool to the new session.
// This exec attempt counts.
assertThrows(XProtocolError.class, "ERROR 5110 \\(HY000\\) Statement with ID=1 was not prepared", testFind::execute);
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.16"))) {
// Mysqlx.Session.Reset doesn't clear PS counters.
assertPreparedStatementsStatusCounts(testSession, 1, 2, 0);
} else {
assertPreparedStatementsStatusCounts(testSession, 0, 1, 0);
}
testFind = testSession.getDefaultSchema().getCollection("testPrepStmtPooling").find();
// 1st execute -> don't prepare.
testFind.execute();
assertPreparedStatementsCountsAndId(testSession, 0, testFind, 0, -1);
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.16"))) {
// Mysqlx.Session.Reset doesn't clear PS counters.
assertPreparedStatementsStatusCounts(testSession, 1, 2, 0);
} else {
assertPreparedStatementsStatusCounts(testSession, 0, 1, 0);
}
// 2nd execute -> prepare + execute.
testFind.execute();
assertPreparedStatementsCountsAndId(testSession, 1, testFind, 1, 1);
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.16"))) {
// Mysqlx.Session.Reset doesn't clear PS counters.
assertPreparedStatementsStatusCounts(testSession, 2, 3, 0);
} else {
assertPreparedStatementsStatusCounts(testSession, 1, 2, 0);
}
assertPreparedStatementsCount(sessionThreadId, 1, 1);
// Prepared statements won't live past closing the client and its sessions.
testClient.close();
assertPreparedStatementsCount(sessionThreadId, 0, 10);
assertThrows(CJCommunicationsException.class, "Unable to write message", testFind::execute);
} finally {
this.schema.dropCollection("testPrepStmtPooling");
}
}
use of com.mysql.cj.xdevapi.Client in project aws-mysql-jdbc by awslabs.
the class SessionTest method testBug97730.
/**
* Tests fix for Bug#97730 (31699993), xdev api: ConcurrentModificationException at Session.close.
*
* @throws Throwable
*/
@Test
public void testBug97730() throws Throwable {
for (String pooling : new String[] { "false", "true" }) {
Properties props = new Properties();
props.setProperty(ClientProperty.POOLING_ENABLED.getKeyName(), pooling);
ClientFactory cf = new ClientFactory();
Client client = cf.getClient(this.baseUrl, props);
List<Future<?>> futures = new ArrayList<>();
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 1000; i++) {
futures.add(executor.submit(() -> {
client.getSession().close();
}));
}
Exception exception = null;
for (Future<?> f : futures) {
try {
f.get();
} catch (ExecutionException e) {
exception = e;
break;
}
}
executor.shutdown();
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
if (exception != null) {
throw exception.getCause();
}
}
}
use of com.mysql.cj.xdevapi.Client in project aws-mysql-jdbc by awslabs.
the class SessionTest method testSessionAttributes_checkClient.
private void testSessionAttributes_checkClient(String url, Map<String, String> userAttributes) throws Exception {
ClientFactory cf = new ClientFactory();
Client c = cf.getClient(url, new Properties());
try {
Session s0 = c.getSession();
testSessionAttributes_checkSession(s0, userAttributes);
// return to pool
s0.close();
// check that pooled session set the same attributes
// get it from pool
Session s1 = c.getSession();
s1.sql("SELECT 1").execute();
assertNotEquals(s0, s1);
Field fProtocol = CoreSession.class.getDeclaredField("protocol");
fProtocol.setAccessible(true);
assertEquals(fProtocol.get(((SessionImpl) s0).getSession()), fProtocol.get(((SessionImpl) s1).getSession()));
testSessionAttributes_checkSession(s1, userAttributes);
} finally {
c.close();
}
}
use of com.mysql.cj.xdevapi.Client in project aws-mysql-jdbc by awslabs.
the class SessionTest method testBug28616573.
@Test
public void testBug28616573() throws Exception {
RowResult res = this.session.sql("select @@global.mysqlx_max_connections, VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Mysqlx_worker_threads_active'").execute();
Row r = res.next();
int mysqlxMaxConnections = r.getInt(0);
int mysqlWorkerThreadsActive = Integer.parseInt(r.getString(1));
// allow only 2 additional connections
this.session.sql("SET @@global.mysqlx_max_connections=" + (mysqlWorkerThreadsActive + 2)).execute();
Properties props = new Properties();
props.setProperty(ClientProperty.POOLING_ENABLED.getKeyName(), "true");
props.setProperty(ClientProperty.POOLING_MAX_SIZE.getKeyName(), "2");
props.setProperty(ClientProperty.POOLING_MAX_IDLE_TIME.getKeyName(), "2000");
props.setProperty(ClientProperty.POOLING_QUEUE_TIMEOUT.getKeyName(), "2000");
try {
ClientFactory cf = new ClientFactory();
Client cli1 = cf.getClient(this.baseUrl, props);
Client cli2 = cf.getClient(this.baseUrl, props);
// new connection #1
Session sess1 = cli1.getSession();
sess1.sql("SELECT 1").execute();
sess1.close();
// reuse connection #1
sess1 = cli1.getSession();
// new connection #2
Session sess2 = cli1.getSession();
sess2.sql("SELECT 1").execute();
assertThrows(CJCommunicationsException.class, "Unable to connect to any of the target hosts\\.", cli2::getSession);
cli1.close();
cli2.close();
} finally {
this.session.sql("SET @@global.mysqlx_max_connections=" + mysqlxMaxConnections).execute();
}
}
Aggregations