use of org.apache.ignite.internal.client.thin.ClientServerError in project ignite by apache.
the class FunctionalTest method testTransactions.
/**
* Test transactions.
*/
@Test
public void testTransactions() throws Exception {
try (Ignite ignite = Ignition.start(Config.getServerConfiguration());
IgniteClient client = Ignition.startClient(getClientConfiguration())) {
ClientCache<Integer, String> cache = client.createCache(new ClientCacheConfiguration().setName("cache").setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL));
cache.put(0, "value0");
cache.put(1, "value1");
// Test nested transactions is not possible.
try (ClientTransaction tx = client.transactions().txStart()) {
try (ClientTransaction tx1 = client.transactions().txStart()) {
fail();
} catch (ClientException expected) {
// No-op.
}
}
// Test implicit rollback when transaction closed.
try (ClientTransaction tx = client.transactions().txStart()) {
cache.put(1, "value2");
}
assertEquals("value1", cache.get(1));
// Test explicit rollback.
try (ClientTransaction tx = client.transactions().txStart()) {
cache.put(1, "value2");
tx.rollback();
}
assertEquals("value1", cache.get(1));
// Test commit.
try (ClientTransaction tx = client.transactions().txStart()) {
cache.put(1, "value2");
tx.commit();
}
assertEquals("value2", cache.get(1));
// Test end of already completed transaction.
ClientTransaction tx0 = client.transactions().txStart();
tx0.close();
try {
tx0.commit();
fail();
} catch (ClientException expected) {
// No-op.
}
// Test end of outdated transaction.
try (ClientTransaction tx = client.transactions().txStart()) {
try {
tx0.commit();
fail();
} catch (ClientException expected) {
// No-op.
}
tx.commit();
}
// Test transaction with a timeout.
long TX_TIMEOUT = 200L;
try (ClientTransaction tx = client.transactions().txStart(PESSIMISTIC, READ_COMMITTED, TX_TIMEOUT)) {
long txStartedTime = U.currentTimeMillis();
cache.put(1, "value3");
while (txStartedTime + TX_TIMEOUT >= U.currentTimeMillis()) U.sleep(100L);
try {
cache.put(1, "value4");
fail();
} catch (ClientException expected) {
// No-op.
}
try {
tx.commit();
fail();
} catch (ClientException expected) {
// No-op.
}
}
assertEquals("value2", cache.get(1));
cache.put(1, "value5");
// Test failover.
ClientProcessorMXBean mxBean = getMxBean(ignite.name(), "Clients", ClientListenerProcessor.class, ClientProcessorMXBean.class);
try (ClientTransaction tx = client.transactions().txStart()) {
cache.put(1, "value6");
mxBean.dropAllConnections();
try {
cache.put(1, "value7");
fail();
} catch (ClientException expected) {
// No-op.
}
// Start new transaction doesn't recover cache operations on failed channel.
try (ClientTransaction tx1 = client.transactions().txStart()) {
fail();
} catch (ClientException expected) {
// No-op.
}
try {
cache.get(1);
fail();
} catch (ClientException expected) {
// No-op.
}
// Close outdated transaction doesn't recover cache operations on failed channel.
tx0.close();
try {
cache.get(1);
fail();
} catch (ClientException expected) {
// No-op.
}
}
assertEquals("value5", cache.get(1));
// Test concurrent transactions in different connections.
try (IgniteClient client1 = Ignition.startClient(getClientConfiguration())) {
ClientCache<Integer, String> cache1 = client1.cache("cache");
try (ClientTransaction tx = client.transactions().txStart(OPTIMISTIC, READ_COMMITTED)) {
cache.put(0, "value8");
try (ClientTransaction tx1 = client1.transactions().txStart(OPTIMISTIC, READ_COMMITTED)) {
assertEquals("value8", cache.get(0));
assertEquals("value0", cache1.get(0));
cache1.put(1, "value9");
assertEquals("value5", cache.get(1));
assertEquals("value9", cache1.get(1));
tx1.commit();
assertEquals("value9", cache.get(1));
}
assertEquals("value0", cache1.get(0));
tx.commit();
assertEquals("value8", cache1.get(0));
}
}
// Check different types of cache operations.
try (ClientTransaction tx = client.transactions().txStart()) {
// Operations: put, putAll, putIfAbsent.
cache.put(2, "value10");
cache.putAll(F.asMap(1, "value11", 3, "value12"));
cache.putIfAbsent(4, "value13");
// Operations: get, getAll, getAndPut, getAndRemove, getAndReplace, getAndPutIfAbsent.
assertEquals("value10", cache.get(2));
assertEquals(F.asMap(1, "value11", 2, "value10"), cache.getAll(new HashSet<>(Arrays.asList(1, 2))));
assertEquals("value13", cache.getAndPut(4, "value14"));
assertEquals("value14", cache.getAndPutIfAbsent(4, "valueDiscarded"));
assertEquals("value14", cache.get(4));
assertEquals("value14", cache.getAndReplace(4, "value15"));
assertEquals("value15", cache.getAndRemove(4));
assertNull(cache.getAndPutIfAbsent(10, "valuePutIfAbsent"));
assertEquals("valuePutIfAbsent", cache.get(10));
// Operations: contains.
assertTrue(cache.containsKey(2));
assertFalse(cache.containsKey(4));
assertTrue(cache.containsKeys(ImmutableSet.of(2, 10)));
assertFalse(cache.containsKeys(ImmutableSet.of(2, 4)));
// Operations: replace.
cache.put(4, "");
assertTrue(cache.replace(4, "value16"));
assertTrue(cache.replace(4, "value16", "value17"));
// Operations: remove, removeAll
cache.putAll(F.asMap(5, "", 6, ""));
assertTrue(cache.remove(5));
assertTrue(cache.remove(4, "value17"));
cache.removeAll(new HashSet<>(Arrays.asList(3, 6)));
assertFalse(cache.containsKey(3));
assertFalse(cache.containsKey(6));
tx.rollback();
}
assertEquals(F.asMap(0, "value8", 1, "value9"), cache.getAll(new HashSet<>(Arrays.asList(0, 1))));
assertFalse(cache.containsKey(2));
// Test concurrent transactions started by different threads.
try (ClientTransaction tx = client.transactions().txStart(PESSIMISTIC, READ_COMMITTED)) {
CyclicBarrier barrier = new CyclicBarrier(2);
cache.put(0, "value18");
IgniteInternalFuture<?> fut = GridTestUtils.runAsync(() -> {
try (ClientTransaction tx1 = client.transactions().txStart(PESSIMISTIC, READ_COMMITTED)) {
cache.put(1, "value19");
barrier.await();
assertEquals("value8", cache.get(0));
barrier.await();
tx1.commit();
barrier.await();
assertEquals("value18", cache.get(0));
} catch (InterruptedException | BrokenBarrierException ignore) {
// No-op.
}
});
barrier.await();
assertEquals("value9", cache.get(1));
barrier.await();
tx.commit();
barrier.await();
assertEquals("value19", cache.get(1));
fut.get();
}
// Test transaction usage by different threads.
try (ClientTransaction tx = client.transactions().txStart(PESSIMISTIC, READ_COMMITTED)) {
cache.put(0, "value20");
GridTestUtils.runAsync(() -> {
// Implicit transaction started here.
cache.put(1, "value21");
assertEquals("value18", cache.get(0));
try {
// Transaction can't be commited by another thread.
tx.commit();
fail();
} catch (ClientException expected) {
// No-op.
}
// Transaction can be closed by another thread.
tx.close();
assertEquals("value18", cache.get(0));
}).get();
assertEquals("value21", cache.get(1));
try {
// Transaction can't be commited after another thread close this transaction.
tx.commit();
fail();
} catch (ClientException expected) {
// No-op.
}
assertEquals("value18", cache.get(0));
// Start implicit transaction after explicit transaction has been closed by another thread.
cache.put(0, "value22");
GridTestUtils.runAsync(() -> assertEquals("value22", cache.get(0))).get();
// New explicit transaction can be started after current transaction has been closed by another thread.
try (ClientTransaction tx1 = client.transactions().txStart(PESSIMISTIC, READ_COMMITTED)) {
cache.put(0, "value23");
tx1.commit();
}
assertEquals("value23", cache.get(0));
}
// Test active transactions limit.
int txLimit = ignite.configuration().getClientConnectorConfiguration().getThinClientConfiguration().getMaxActiveTxPerConnection();
List<ClientTransaction> txs = new ArrayList<>(txLimit);
for (int i = 0; i < txLimit; i++) {
Thread t = new Thread(() -> txs.add(client.transactions().txStart()));
t.start();
t.join();
}
try (ClientTransaction ignored = client.transactions().txStart()) {
fail();
} catch (ClientException e) {
ClientServerError cause = (ClientServerError) e.getCause();
assertEquals(ClientStatus.TX_LIMIT_EXCEEDED, cause.getCode());
}
for (ClientTransaction tx : txs) tx.close();
// Test that new transaction can be started after commit of the previous one without closing.
ClientTransaction tx = client.transactions().txStart();
tx.commit();
tx = client.transactions().txStart();
tx.rollback();
// Test that new transaction can be started after rollback of the previous one without closing.
tx = client.transactions().txStart();
tx.commit();
// Test that implicit transaction started after commit of previous one without closing.
cache.put(0, "value24");
GridTestUtils.runAsync(() -> assertEquals("value24", cache.get(0))).get();
}
}
Aggregations