use of org.apache.ignite.internal.processors.cache.persistence.wal.WALPointer in project ignite by apache.
the class CdcCacheVersionTest method testConflictVersionWritten.
/**
* Test that conflict version is writtern to WAL.
*/
@Test
public void testConflictVersionWritten() throws Exception {
walProvider = (ctx) -> new FileWriteAheadLogManager(ctx) {
@Override
public WALPointer log(WALRecord rec) throws IgniteCheckedException {
if (rec.type() != DATA_RECORD_V2)
return super.log(rec);
DataRecord dataRec = (DataRecord) rec;
for (int i = 0; i < dataRec.entryCount(); i++) {
DataEntry dataEntry = dataRec.writeEntries().get(i);
assertEquals(CU.cacheId(DEFAULT_CACHE_NAME), dataEntry.cacheId());
assertEquals(DFLT_CLUSTER_ID, dataEntry.writeVersion().dataCenterId());
assertNotNull(dataEntry.writeVersion().conflictVersion());
assertEquals(OTHER_CLUSTER_ID, dataEntry.writeVersion().conflictVersion().dataCenterId());
walRecCheckedCntr.incrementAndGet();
}
return super.log(rec);
}
};
conflictResolutionMgrSupplier = () -> new CacheVersionConflictResolver() {
@Override
public <K1, V1> GridCacheVersionConflictContext<K1, V1> resolve(CacheObjectValueContext ctx, GridCacheVersionedEntryEx<K1, V1> oldEntry, GridCacheVersionedEntryEx<K1, V1> newEntry, boolean atomicVerComparator) {
GridCacheVersionConflictContext<K1, V1> res = new GridCacheVersionConflictContext<>(ctx, oldEntry, newEntry);
res.useNew();
assertEquals(OTHER_CLUSTER_ID, newEntry.version().dataCenterId());
if (!oldEntry.isStartVersion())
assertEquals(OTHER_CLUSTER_ID, oldEntry.version().dataCenterId());
conflictCheckedCntr.incrementAndGet();
return res;
}
@Override
public String toString() {
return "TestCacheConflictResolutionManager";
}
};
startGrids(gridCnt);
IgniteEx cli = startClientGrid(gridCnt);
for (int i = 0; i < gridCnt; i++) {
grid(i).context().cache().context().versions().dataCenterId(DFLT_CLUSTER_ID);
assertEquals(DFLT_CLUSTER_ID, grid(i).context().metric().registry(CACHE_METRICS).<IntMetric>findMetric(DATA_VER_CLUSTER_ID).value());
}
cli.cluster().state(ACTIVE);
IgniteCache<Integer, User> cache = cli.getOrCreateCache(new CacheConfiguration<Integer, User>(DEFAULT_CACHE_NAME).setCacheMode(cacheMode).setAtomicityMode(atomicityMode).setBackups(Integer.MAX_VALUE));
if (atomicityMode == ATOMIC)
putRemoveCheck(cli, cache, null, null);
else {
// Check operations for transaction cache without explicit transaction.
putRemoveCheck(cli, cache, null, null);
// Check operations for transaction cache with explicit transaction in all modes.
for (TransactionConcurrency concurrency : TransactionConcurrency.values()) for (TransactionIsolation isolation : TransactionIsolation.values()) putRemoveCheck(cli, cache, concurrency, isolation);
}
for (int i = 0; i < gridCnt; i++) {
boolean dfltCacheFound = false;
assertFalse(grid(i).context().clientNode());
SystemView<CacheView> caches = grid(i).context().systemView().view(CACHES_VIEW);
for (CacheView v : caches) {
if (v.cacheName().equals(DEFAULT_CACHE_NAME)) {
assertEquals(v.conflictResolver(), "TestCacheConflictResolutionManager");
dfltCacheFound = true;
} else
assertNull(v.conflictResolver());
}
assertTrue(dfltCacheFound);
}
}
use of org.apache.ignite.internal.processors.cache.persistence.wal.WALPointer in project ignite by apache.
the class AbstractCdcTest method createCdc.
/**
*/
protected CdcMain createCdc(CdcConsumer cnsmr, IgniteConfiguration cfg, CountDownLatch latch, GridAbsPredicate... conditions) {
CdcConfiguration cdcCfg = new CdcConfiguration();
cdcCfg.setConsumer(cnsmr);
cdcCfg.setKeepBinary(keepBinary());
cdcCfg.setMetricExporterSpi(metricExporters());
return new CdcMain(cfg, null, cdcCfg) {
@Override
protected CdcConsumerState createState(Path stateDir) {
return new CdcConsumerState(stateDir) {
@Override
public void save(WALPointer ptr) throws IOException {
super.save(ptr);
if (!F.isEmpty(conditions)) {
for (GridAbsPredicate p : conditions) {
if (!p.apply())
return;
}
latch.countDown();
}
}
};
}
};
}
use of org.apache.ignite.internal.processors.cache.persistence.wal.WALPointer in project ignite by apache.
the class GridCacheMapEntry method innerRemove.
/**
* {@inheritDoc}
*/
@Override
public final GridCacheUpdateTxResult innerRemove(@Nullable IgniteInternalTx tx, UUID evtNodeId, UUID affNodeId, boolean retval, boolean evt, boolean metrics, boolean keepBinary, boolean oldValPresent, @Nullable CacheObject oldVal, AffinityTopologyVersion topVer, CacheEntryPredicate[] filter, GridDrType drType, @Nullable GridCacheVersion explicitVer, String taskName, @Nullable GridCacheVersion dhtVer, @Nullable Long updateCntr) throws IgniteCheckedException, GridCacheEntryRemovedException {
assert cctx.transactional();
CacheObject old;
GridCacheVersion newVer;
final boolean valid = valid(tx != null ? tx.topologyVersion() : topVer);
// Lock should be held by now.
if (!cctx.isAll(this, filter))
return new GridCacheUpdateTxResult(false);
GridCacheVersion obsoleteVer = null;
boolean intercept = cctx.config().getInterceptor() != null;
IgniteBiTuple<Boolean, Object> interceptRes = null;
CacheLazyEntry entry0 = null;
long updateCntr0;
WALPointer logPtr = null;
boolean deferred;
boolean marked = false;
lockListenerReadLock();
lockEntry();
try {
checkObsolete();
if (isNear()) {
assert dhtVer != null;
// It is possible that 'get' could load more recent value.
if (!((GridNearCacheEntry) this).recordDhtVersion(dhtVer))
return new GridCacheUpdateTxResult(false, logPtr);
}
assert tx == null || (!tx.local() && tx.onePhaseCommit()) || tx.ownsLock(this) : "Transaction does not own lock for remove[entry=" + this + ", tx=" + tx + ']';
boolean startVer = isStartVersion();
newVer = explicitVer != null ? explicitVer : tx == null ? nextVersion() : tx.writeVersion();
boolean internal = isInternal() || !context().userCache();
Map<UUID, CacheContinuousQueryListener> lsnrCol = notifyContinuousQueries() ? cctx.continuousQueries().updateListeners(internal, false) : null;
if (startVer && (retval || intercept || lsnrCol != null))
unswap();
old = oldValPresent ? oldVal : val;
if (intercept)
intercept = !skipInterceptor(explicitVer);
if (intercept) {
entry0 = new CacheLazyEntry(cctx, key, old, keepBinary);
interceptRes = cctx.config().getInterceptor().onBeforeRemove(entry0);
if (cctx.cancelRemove(interceptRes)) {
CacheObject ret = cctx.toCacheObject(cctx.unwrapTemporary(interceptRes.get2()));
return new GridCacheUpdateTxResult(false, logPtr);
}
}
removeValue();
update(null, 0, 0, newVer, true);
if (cctx.deferredDelete() && !detached() && !isInternal()) {
if (!deletedUnlocked()) {
deletedUnlocked(true);
if (tx != null) {
GridCacheMvcc mvcc = mvccExtras();
if (mvcc == null || mvcc.isEmpty(tx.xidVersion()))
clearReaders();
else {
// Optimize memory usage - do not allocate additional array.
List<GridCacheMvccCandidate> locs = mvcc.localCandidatesNoCopy(false);
GridCacheVersion txVer = tx.xidVersion();
UUID originatingNodeId = tx.originatingNodeId();
boolean hasOriginatingNodeId = false;
for (GridCacheMvccCandidate c : locs) {
if (c.reentry() || Objects.equals(c.version(), txVer))
continue;
if (Objects.equals(c.otherNodeId(), originatingNodeId)) {
hasOriginatingNodeId = true;
break;
}
}
// Remove reader only if there are no other active transactions from it.
if (!hasOriginatingNodeId)
clearReader(originatingNodeId);
}
}
}
}
updateCntr0 = nextPartitionCounter(tx, updateCntr);
if (tx != null && cctx.group().persistenceEnabled() && cctx.group().walEnabled())
logPtr = logTxUpdate(tx, null, addConflictVersion(tx.writeVersion(), newVer), 0, updateCntr0);
drReplicate(drType, null, newVer, topVer);
if (metrics && cctx.statisticsEnabled()) {
cctx.cache().metrics0().onRemove();
T2<GridCacheOperation, CacheObject> entryProcRes = tx.entry(txKey()).entryProcessorCalculatedValue();
if (entryProcRes != null && DELETE.equals(entryProcRes.get1()))
cctx.cache().metrics0().onInvokeRemove(old != null);
}
if (tx == null)
obsoleteVer = newVer;
else {
// Only delete entry if the lock is not explicit.
if (lockedBy(tx.xidVersion()))
obsoleteVer = tx.xidVersion();
else if (log.isDebugEnabled())
log.debug("Obsolete version was not set because lock was explicit: " + this);
}
if (evt && newVer != null && cctx.events().isRecordable(EVT_CACHE_OBJECT_REMOVED)) {
CacheObject evtOld = cctx.unwrapTemporary(old);
cctx.events().addEvent(partition(), key, evtNodeId, tx, null, newVer, EVT_CACHE_OBJECT_REMOVED, null, false, evtOld, evtOld != null || hasValueUnlocked(), null, taskName, keepBinary);
}
if (lsnrCol != null) {
cctx.continuousQueries().onEntryUpdated(lsnrCol, key, null, old, internal, partition(), tx.local(), false, updateCntr0, null, topVer);
}
deferred = cctx.deferredDelete() && !detached();
if (intercept)
entry0.updateCounter(updateCntr0);
if (!deferred) {
// If entry is still removed.
assert newVer == ver;
if (obsoleteVer == null || !(marked = markObsolete0(obsoleteVer, true, null))) {
if (log.isDebugEnabled())
log.debug("Entry could not be marked obsolete (it is still used): " + this);
} else {
recordNodeId(affNodeId, topVer);
if (log.isDebugEnabled())
log.debug("Entry was marked obsolete: " + this);
}
}
} finally {
unlockEntry();
unlockListenerReadLock();
}
if (marked) {
assert !deferred;
onMarkedObsolete();
}
onUpdateFinished(updateCntr0);
if (intercept)
cctx.config().getInterceptor().onAfterRemove(entry0);
if (valid)
return new GridCacheUpdateTxResult(true, updateCntr0, logPtr);
else
return new GridCacheUpdateTxResult(false, logPtr);
}
use of org.apache.ignite.internal.processors.cache.persistence.wal.WALPointer in project ignite by apache.
the class GridCacheMapEntry method mvccLock.
/**
* {@inheritDoc}
*/
@Override
public GridCacheUpdateTxResult mvccLock(GridDhtTxLocalAdapter tx, MvccSnapshot mvccVer) throws GridCacheEntryRemovedException, IgniteCheckedException {
assert tx != null;
assert mvccVer != null;
final boolean valid = valid(tx.topologyVersion());
final GridCacheVersion newVer;
WALPointer logPtr = null;
lockEntry();
try {
checkObsolete();
newVer = tx.writeVersion();
assert newVer != null : "Failed to get write version for tx: " + tx;
assert tx.local();
MvccUpdateResult res = cctx.offheap().mvccLock(this, mvccVer);
assert res != null;
if (res.resultType() == ResultType.VERSION_MISMATCH)
throw serializationError();
else if (res.resultType() == ResultType.LOCKED) {
unlockEntry();
MvccVersion lockVer = res.resultVersion();
GridFutureAdapter<GridCacheUpdateTxResult> resFut = new GridFutureAdapter<>();
IgniteInternalFuture<?> lockFut = cctx.kernalContext().coordinators().waitForLock(cctx, mvccVer, lockVer);
lockFut.listen(new MvccAcquireLockListener(tx, this, mvccVer, resFut));
return new GridCacheUpdateTxResult(false, resFut);
}
} finally {
if (lockedByCurrentThread()) {
unlockEntry();
cctx.evicts().touch(this);
}
}
onUpdateFinished(0L);
return new GridCacheUpdateTxResult(valid, logPtr);
}
use of org.apache.ignite.internal.processors.cache.persistence.wal.WALPointer in project ignite by apache.
the class GridCacheMapEntry method innerSet.
/**
* {@inheritDoc}
*/
@Override
public final GridCacheUpdateTxResult innerSet(@Nullable IgniteInternalTx tx, UUID evtNodeId, UUID affNodeId, CacheObject val, boolean writeThrough, boolean retval, long ttl, boolean evt, boolean metrics, boolean keepBinary, boolean oldValPresent, @Nullable CacheObject oldVal, AffinityTopologyVersion topVer, CacheEntryPredicate[] filter, GridDrType drType, long drExpireTime, @Nullable GridCacheVersion explicitVer, String taskName, @Nullable GridCacheVersion dhtVer, @Nullable Long updateCntr) throws IgniteCheckedException, GridCacheEntryRemovedException {
CacheObject old;
final boolean valid = valid(tx != null ? tx.topologyVersion() : topVer);
// Lock should be held by now.
if (!cctx.isAll(this, filter))
return new GridCacheUpdateTxResult(false);
final GridCacheVersion newVer;
boolean intercept = cctx.config().getInterceptor() != null;
Object key0 = null;
Object val0 = null;
WALPointer logPtr = null;
long updateCntr0;
ensureFreeSpace();
lockListenerReadLock();
lockEntry();
try {
checkObsolete();
if (isNear()) {
assert dhtVer != null;
// It is possible that 'get' could load more recent value.
if (!((GridNearCacheEntry) this).recordDhtVersion(dhtVer))
return new GridCacheUpdateTxResult(false, logPtr);
}
assert tx == null || (!tx.local() && tx.onePhaseCommit()) || tx.ownsLock(this) : "Transaction does not own lock for update [entry=" + this + ", tx=" + tx + ']';
// Load and remove from swap if it is new.
boolean startVer = isStartVersion();
boolean internal = isInternal() || !context().userCache();
Map<UUID, CacheContinuousQueryListener> lsnrCol = notifyContinuousQueries() ? cctx.continuousQueries().updateListeners(internal, false) : null;
if (startVer && (retval || intercept || lsnrCol != null))
unswap(retval);
newVer = explicitVer != null ? explicitVer : tx == null ? nextVersion() : tx.writeVersion();
assert newVer != null : "Failed to get write version for tx: " + tx;
old = oldValPresent ? oldVal : this.val;
if (intercept)
intercept = !skipInterceptor(explicitVer);
if (intercept) {
val0 = cctx.unwrapBinaryIfNeeded(val, keepBinary, false, null);
CacheLazyEntry e = new CacheLazyEntry(cctx, key, old, keepBinary);
key0 = e.key();
Object interceptorVal = cctx.config().getInterceptor().onBeforePut(e, val0);
if (interceptorVal == null)
return new GridCacheUpdateTxResult(false, logPtr);
else if (interceptorVal != val0)
val0 = cctx.unwrapTemporary(interceptorVal);
val = cctx.toCacheObject(val0);
}
// Determine new ttl and expire time.
long expireTime;
if (drExpireTime >= 0) {
assert ttl >= 0 : ttl;
expireTime = drExpireTime;
} else {
if (ttl == -1L) {
ttl = ttlExtras();
expireTime = expireTimeExtras();
} else
expireTime = CU.toExpireTime(ttl);
}
assert ttl >= 0 : ttl;
assert expireTime >= 0 : expireTime;
// Detach value before index update.
val = cctx.kernalContext().cacheObjects().prepareForCache(val, cctx);
assert val != null;
storeValue(val, expireTime, newVer);
if (cctx.deferredDelete() && deletedUnlocked() && !isInternal() && !detached())
deletedUnlocked(false);
updateCntr0 = nextPartitionCounter(tx, updateCntr);
if (tx != null && cctx.group().persistenceEnabled() && cctx.group().walEnabled())
logPtr = logTxUpdate(tx, val, addConflictVersion(tx.writeVersion(), newVer), expireTime, updateCntr0);
update(val, expireTime, ttl, newVer, true);
drReplicate(drType, val, newVer, topVer);
recordNodeId(affNodeId, topVer);
if (metrics && cctx.statisticsEnabled() && tx != null) {
cctx.cache().metrics0().onWrite();
IgniteTxEntry txEntry = tx.entry(txKey());
if (txEntry != null) {
T2<GridCacheOperation, CacheObject> entryProcRes = txEntry.entryProcessorCalculatedValue();
if (entryProcRes != null && UPDATE.equals(entryProcRes.get1()))
cctx.cache().metrics0().onInvokeUpdate(old != null);
}
}
if (evt && newVer != null && cctx.events().isRecordable(EVT_CACHE_OBJECT_PUT)) {
CacheObject evtOld = cctx.unwrapTemporary(old);
cctx.events().addEvent(partition(), key, evtNodeId, tx, null, newVer, EVT_CACHE_OBJECT_PUT, val, val != null, evtOld, evtOld != null || hasValueUnlocked(), null, taskName, keepBinary);
}
if (lsnrCol != null) {
cctx.continuousQueries().onEntryUpdated(lsnrCol, key, val, old, internal, partition(), tx.local(), false, updateCntr0, null, topVer);
}
} finally {
unlockEntry();
unlockListenerReadLock();
}
onUpdateFinished(updateCntr0);
if (log.isDebugEnabled())
log.debug("Updated cache entry [val=" + val + ", old=" + old + ", entry=" + this + ']');
// value will be handled by current transaction.
if (writeThrough)
cctx.store().put(tx, key, val, newVer);
if (intercept)
cctx.config().getInterceptor().onAfterPut(new CacheLazyEntry(cctx, key, key0, val, val0, keepBinary, updateCntr0));
updatePlatformCache(val, topVer);
return valid ? new GridCacheUpdateTxResult(true, updateCntr0, logPtr) : new GridCacheUpdateTxResult(false, logPtr);
}
Aggregations