use of org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition in project ignite by apache.
the class CacheDeferredDeleteQueueTest method testQueue.
/**
* @param atomicityMode Cache atomicity mode.
* @param nearCache {@code True} if need create near cache.
*
* @throws Exception If failed.
*/
private void testQueue(CacheAtomicityMode atomicityMode, boolean nearCache) throws Exception {
CacheConfiguration<Integer, Integer> ccfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
ccfg.setCacheMode(PARTITIONED);
ccfg.setAtomicityMode(atomicityMode);
ccfg.setWriteSynchronizationMode(FULL_SYNC);
ccfg.setBackups(1);
if (nearCache)
ccfg.setNearConfiguration(new NearCacheConfiguration<Integer, Integer>());
IgniteCache<Integer, Integer> cache = ignite(0).createCache(ccfg);
try {
final int KEYS = cache.getConfiguration(CacheConfiguration.class).getAffinity().partitions() * 3;
for (int i = 0; i < KEYS; i++) cache.put(i, i);
for (int i = 0; i < KEYS; i++) cache.remove(i);
boolean wait = GridTestUtils.waitForCondition(new GridAbsPredicate() {
@Override
public boolean apply() {
for (int i = 0; i < NODES; i++) {
final GridDhtPartitionTopology top = ((IgniteKernal) ignite(i)).context().cache().cache(DEFAULT_CACHE_NAME).context().topology();
for (GridDhtLocalPartition p : top.currentLocalPartitions()) {
Collection<Object> rmvQueue = GridTestUtils.getFieldValue(p, "rmvQueue");
if (!rmvQueue.isEmpty() || p.dataStore().fullSize() != 0)
return false;
}
}
return true;
}
}, 5000);
assertTrue("Failed to wait for rmvQueue cleanup.", wait);
} finally {
ignite(0).destroyCache(ccfg.getName());
}
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition in project ignite by apache.
the class IgniteCacheGroupsTest method testRestartsAndCacheCreateDestroy.
/**
* @throws Exception If failed.
*/
@Test
public void testRestartsAndCacheCreateDestroy() throws Exception {
final int SRVS = 5;
startGrids(SRVS);
final Ignite clientNode = startClientGrid(SRVS);
final int CACHES = SF.applyLB(10, 2);
final AtomicReferenceArray<IgniteCache> caches = new AtomicReferenceArray<>(CACHES);
for (int i = 0; i < CACHES; i++) {
CacheAtomicityMode atomicityMode = i % 2 == 0 ? ATOMIC : TRANSACTIONAL;
caches.set(i, clientNode.createCache(cacheConfiguration(GROUP1, "c" + i, PARTITIONED, atomicityMode, 0, false)));
}
final AtomicBoolean stop = new AtomicBoolean();
final AtomicInteger cacheCntr = new AtomicInteger();
try {
final int ITERATIONS_COUNT = SF.applyLB(10, 1);
for (int i = 0; i < ITERATIONS_COUNT; i++) {
stop.set(false);
final AtomicReference<Exception> err = new AtomicReference<>();
log.info("Iteration: " + i);
IgniteInternalFuture<?> restartFut = GridTestUtils.runAsync(new Runnable() {
@Override
public void run() {
try {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
while (!stop.get()) {
int node = rnd.nextInt(SRVS);
log.info("Stop node: " + node);
stopGrid(node);
U.sleep(500);
log.info("Start node: " + node);
startGrid(node);
try {
if (rnd.nextBoolean())
awaitPartitionMapExchange();
} catch (Exception ignore) {
// No-op.
}
}
} catch (Exception e) {
log.error("Unexpected error: " + e, e);
err.set(e);
stop.set(true);
}
}
});
IgniteInternalFuture<?> cacheFut = GridTestUtils.runAsync(new Runnable() {
@Override
public void run() {
try {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
while (!stop.get()) {
int idx = rnd.nextInt(CACHES);
IgniteCache cache = caches.get(idx);
if (cache != null && caches.compareAndSet(idx, cache, null)) {
log.info("Destroy cache: " + cache.getName());
clientNode.destroyCache(cache.getName());
CacheAtomicityMode atomicityMode = rnd.nextBoolean() ? ATOMIC : TRANSACTIONAL;
String name = "newName-" + cacheCntr.incrementAndGet();
cache = clientNode.createCache(cacheConfiguration(GROUP1, name, PARTITIONED, atomicityMode, 0, false));
caches.set(idx, cache);
}
}
} catch (Exception e) {
log.error("Unexpected error: " + e, e);
err.set(e);
stop.set(true);
}
}
});
IgniteInternalFuture opFut = GridTestUtils.runMultiThreadedAsync(new Runnable() {
@Override
public void run() {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
while (!stop.get()) {
try {
int idx = rnd.nextInt(CACHES);
IgniteCache cache = caches.get(idx);
if (cache != null && caches.compareAndSet(idx, cache, null)) {
try {
for (int i = 0; i < 10; i++) cacheOperation(rnd, cache);
} catch (Exception e) {
if (X.hasCause(e, CacheStoppedException.class) || (X.hasCause(e, CacheInvalidStateException.class) && X.hasCause(e, TransactionRollbackException.class))) {
// if a node was stopped during transaction.
continue;
}
throw e;
} finally {
caches.set(idx, cache);
}
}
} catch (Exception e) {
err.set(e);
log.error("Unexpected error: " + e, e);
stop.set(true);
}
}
}
}, 8, "op-thread");
Thread.sleep(SF.applyLB(10_000, 1_000));
stop.set(true);
restartFut.get();
cacheFut.get();
opFut.get();
assertNull("Unexpected error during test, see log for details", err.get());
awaitPartitionMapExchange();
Set<Integer> cacheIds = new HashSet<>();
for (int c = 0; c < CACHES; c++) {
IgniteCache cache = caches.get(c);
assertNotNull(cache);
assertTrue(cacheIds.add(CU.cacheId(cache.getName())));
}
for (int n = 0; n < SRVS; n++) {
CacheGroupContext grp = cacheGroup(ignite(n), GROUP1);
assertNotNull(grp);
for (GridDhtLocalPartition part : grp.topology().currentLocalPartitions()) {
IntMap<Object> cachesMap = GridTestUtils.getFieldValue(part, "cacheMaps");
assertTrue(cachesMap.size() <= cacheIds.size());
cachesMap.forEach((cacheId, v) -> assertTrue(cachesMap.containsKey(cacheId)));
}
}
}
} finally {
stop.set(true);
}
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition in project ignite by apache.
the class GridCachePartitionedUnloadEventsSelfTest method checkPartitionUnloadEvents.
/**
* @param evts Events.
* @param g Grid.
* @param parts Parts.
*/
private void checkPartitionUnloadEvents(Collection<Event> evts, Ignite g, Collection<GridDhtLocalPartition> parts) {
assertEquals(parts.size(), evts.size());
for (Event evt : evts) {
CacheRebalancingEvent unloadEvt = (CacheRebalancingEvent) evt;
final int part = unloadEvt.partition();
assertNotNull("Unexpected partition: " + part, F.find(parts, null, new IgnitePredicate<GridDhtLocalPartition>() {
@Override
public boolean apply(GridDhtLocalPartition e) {
return e.id() == part;
}
}));
assertEquals(g.cache(DEFAULT_CACHE_NAME).getName(), unloadEvt.cacheName());
assertEquals(g.cluster().localNode().id(), unloadEvt.node().id());
}
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition in project ignite by apache.
the class IgnitePdsCacheEntriesExpirationTest method testDeadlockBetweenCachePutAndEntryExpiration.
/**
* Verifies scenario of a deadlock between thread, modifying a cache entry (acquires cp read lock and entry lock),
* ttl thread, expiring the entry (acquires cp read lock and entry lock) and checkpoint thread (acquires cp write
* lock).
*
* Checkpoint thread in not used but emulated by the test to avoid test hang (interruptible API for acquiring write
* lock is used).
*
* For more details see <a href="https://ggsystems.atlassian.net/browse/GG-23135">GG-23135</a>.
*
* <p> <strong>Important note</strong> Implementation of this test relies heavily on structure of existing code in
* {@link GridCacheOffheapManager.GridCacheDataStore#purgeExpiredInternal(GridCacheContext, IgniteInClosure2X, int)}
* and {@link GridCacheMapEntry#onExpired(CacheObject, GridCacheVersion)} methods.
*
* Any changes to those methods could break logic inside the test so if new failures of the test occure test code
* itself may require refactoring. </p>
*
* @throws Exception If failed.
*/
@Test
public void testDeadlockBetweenCachePutAndEntryExpiration() throws Exception {
AtomicBoolean timeoutReached = new AtomicBoolean(false);
AtomicBoolean cpWriteLocked = new AtomicBoolean(false);
AtomicInteger partId = new AtomicInteger();
CountDownLatch ttlLatch = new CountDownLatch(2);
IgniteEx srv0 = startGrids(2);
srv0.cluster().active(true);
awaitPartitionMapExchange();
srv0.getOrCreateCache(DEFAULT_CACHE_NAME);
GridDhtPartitionTopologyImpl top = (GridDhtPartitionTopologyImpl) srv0.cachex(DEFAULT_CACHE_NAME).context().topology();
top.partitionFactory((ctx, grp, id, recovery) -> {
partId.set(id);
return new GridDhtLocalPartition(ctx, grp, id, recovery) {
/**
* This method is modified to bring threads in deadlock situation.
* Idea is the following: updater thread (see code below) on its way to
* {@link GridCacheMapEntry#onExpired(CacheObject, GridCacheVersion)} call stops here
* (already having entry lock acquired) and waits until checkpoint write lock is acquired
* by another special thread imulating checkpointer thread (cp-write-lock-holder, see code below).
* After that it enables ttl-cleanup-worker thread to proceed
* (by counting down ttLatch, see next overridden method) and reproduce deadlock scenario.
*/
@Override
public IgniteCacheOffheapManager.CacheDataStore dataStore() {
Thread t = Thread.currentThread();
String tName = t.getName();
if (tName == null || !tName.contains("updater"))
return super.dataStore();
boolean unswapFoundInST = false;
for (StackTraceElement e : t.getStackTrace()) {
if (e.getMethodName().contains("unswap")) {
unswapFoundInST = true;
break;
}
}
if (!unswapFoundInST)
return super.dataStore();
while (!cpWriteLocked.get()) {
try {
Thread.sleep(10);
} catch (InterruptedException ignored) {
log.warning(">>> Thread caught InterruptedException while waiting " + "for cp write lock to be locked");
}
}
ttlLatch.countDown();
return super.dataStore();
}
/**
* This method is modified to bring threads in deadlock situation.
* Idea is the following: internal ttl-cleanup-worker thread wakes up to cleanup expired entries,
* reaches this method after calling purgeExpiredInternal (thus having checkpoint readlock acquired)
* and stops on ttlLatch until updater thread comes in, acquires entry lock and gets stuck
* on acquiring cp read lock
* (because of special cp-write-lock-holder thread already holding cp write lock).
*
* So situation of three threads stuck in deadlock is reproduced.
*/
@Override
public boolean reserve() {
Thread t = Thread.currentThread();
String tName = t.getName();
if (tName == null || !tName.contains("ttl-cleanup-worker"))
return super.reserve();
boolean purgeExpiredFoundInST = false;
for (StackTraceElement e : t.getStackTrace()) {
if (e.getMethodName().contains("purgeExpiredInternal")) {
purgeExpiredFoundInST = true;
break;
}
}
if (!purgeExpiredFoundInST)
return super.reserve();
ttlLatch.countDown();
try {
ttlLatch.await();
} catch (InterruptedException ignored) {
log.warning(">>> Thread caught InterruptedException while waiting for ttl latch" + " to be released by updater thread");
}
return super.reserve();
}
};
});
stopGrid(1);
// change BLT to force new partition creation with modified GridDhtLocalPartition class
srv0.cluster().setBaselineTopology(srv0.cluster().topologyVersion());
Thread.sleep(500);
IgniteCache<Object, Object> cache = srv0.getOrCreateCache(DEFAULT_CACHE_NAME);
GridCacheDatabaseSharedManager db = (GridCacheDatabaseSharedManager) srv0.context().cache().context().database();
CheckpointReadWriteLock checkpointReadWriteLock = U.field(db.checkpointManager.checkpointTimeoutLock(), "checkpointReadWriteLock");
ReentrantReadWriteLockWithTracking rwLock = U.field(checkpointReadWriteLock, "checkpointLock");
int key = 0;
while (true) {
if (srv0.affinity(DEFAULT_CACHE_NAME).partition(key) != partId.get())
key++;
else
break;
}
cache.put(key, 1);
int finalKey = key;
IgniteInternalFuture updateFut = GridTestUtils.runAsync(() -> {
log.info(">>> Updater thread has started, updating key " + finalKey);
int i = 10;
while (!timeoutReached.get()) {
cache.put(finalKey, i++);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
log.warning(">>> Updater thread sleep was interrupted");
}
}
}, "updater-thread");
IgniteInternalFuture writeLockHolderFut = GridTestUtils.runAsync(() -> {
while (ttlLatch.getCount() != 1) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
log.warning(">>> Write lock holder thread sleep was interrupted");
break;
}
}
try {
cpWriteLocked.set(true);
rwLock.writeLock().lockInterruptibly();
ttlLatch.await();
} catch (InterruptedException e) {
log.warning(">>> Write lock holder thread was interrupted while obtaining write lock.");
} finally {
rwLock.writeLock().unlock();
}
}, "cp-write-lock-holder");
GridTestUtils.runAsync(() -> {
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < TIMEOUT) doSleep(1_000);
timeoutReached.set(true);
});
try {
updateFut.get(TIMEOUT * 2);
} catch (IgniteFutureTimeoutCheckedException ignored) {
fail("Failed to wait for futures for doubled timeout");
} finally {
while (ttlLatch.getCount() > 0) ttlLatch.countDown();
writeLockHolderFut.cancel();
updateFut.cancel();
}
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition in project ignite by apache.
the class IgniteAbsentEvictionNodeOutOfBaselineTest method testPartitionsRemovedIfJoiningNodeNotInBaseline.
/**
* Removed partitions if node is out of baseline.
*/
@Test
public void testPartitionsRemovedIfJoiningNodeNotInBaseline() throws Exception {
// given: start 3 nodes with data
Ignite ignite0 = startGrids(3);
ignite0.cluster().baselineAutoAdjustEnabled(false);
ignite0.cluster().active(true);
IgniteCache<Object, Object> cache = ignite0.getOrCreateCache(TEST_CACHE_NAME);
for (int i = 0; i < 100; i++) cache.put(i, i);
// when: stop one node and reset baseline topology
stopGrid(2);
resetBaselineTopology();
ignite0.resetLostPartitions(Collections.singleton(TEST_CACHE_NAME));
awaitPartitionMapExchange();
for (int i = 0; i < 200; i++) cache.put(i, i);
// then: after returning stopped node to grid its partitions should be removed
IgniteEx ignite2 = startGrid(2);
List<GridDhtLocalPartition> partitions = ignite2.cachex(TEST_CACHE_NAME).context().topology().localPartitions();
assertTrue("Should be empty : " + partitions, partitions.isEmpty());
}
Aggregations