use of org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException in project ignite by apache.
the class GridNearOptimisticSerializableTxPrepareFuture method onOwnerChanged.
/**
* {@inheritDoc}
*/
@Override
public boolean onOwnerChanged(GridCacheEntryEx entry, GridCacheMvccCandidate owner) {
if (log.isDebugEnabled())
log.debug("Transaction future received owner changed callback: " + entry);
if ((entry.context().isNear() || entry.context().isLocal()) && owner != null) {
IgniteTxEntry txEntry = tx.entry(entry.txKey());
if (txEntry != null) {
if (entry.context().isLocal()) {
GridCacheVersion serReadVer = txEntry.entryReadVersion();
if (serReadVer != null) {
GridCacheContext ctx = entry.context();
while (true) {
try {
if (!entry.checkSerializableReadVersion(serReadVer)) {
Object key = entry.key().value(ctx.cacheObjectContext(), false);
IgniteTxOptimisticCheckedException err0 = new IgniteTxOptimisticCheckedException(S.toString("Failed to prepare transaction, read/write conflict", "key", key, true, "cache", ctx.name(), false));
ERR_UPD.compareAndSet(this, null, err0);
}
break;
} catch (GridCacheEntryRemovedException ignored) {
entry = ctx.cache().entryEx(entry.key(), tx.topologyVersion());
txEntry.cached(entry);
}
}
}
}
if (keyLockFut != null)
keyLockFut.onKeyLocked(entry.txKey());
return true;
}
}
return false;
}
use of org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException in project ignite by apache.
the class GridNearOptimisticTxPrepareFuture method map.
/**
* @param entry Transaction entry.
* @param topVer Topology version.
* @param cur Current mapping.
* @param topLocked {@code True} if thread already acquired lock preventing topology change.
* @param remap Remap flag.
* @return Mapping.
*/
private GridDistributedTxMapping map(IgniteTxEntry entry, AffinityTopologyVersion topVer, @Nullable GridDistributedTxMapping cur, boolean topLocked, boolean remap) {
GridCacheContext cacheCtx = entry.context();
List<ClusterNode> nodes;
GridCacheEntryEx cached0 = entry.cached();
if (cached0.isDht())
nodes = cacheCtx.topology().nodes(cached0.partition(), topVer);
else
nodes = cacheCtx.isLocal() ? cacheCtx.affinity().nodesByKey(entry.key(), topVer) : cacheCtx.topology().nodes(cacheCtx.affinity().partition(entry.key()), topVer);
if (F.isEmpty(nodes)) {
ClusterTopologyServerNotFoundException e = new ClusterTopologyServerNotFoundException("Failed to map " + "keys to nodes (partition is not mapped to any node) [key=" + entry.key() + ", partition=" + cacheCtx.affinity().partition(entry.key()) + ", topVer=" + topVer + ']');
onDone(e);
return null;
}
txMapping.addMapping(nodes);
ClusterNode primary = F.first(nodes);
assert primary != null;
if (log.isDebugEnabled()) {
log.debug("Mapped key to primary node [key=" + entry.key() + ", part=" + cacheCtx.affinity().partition(entry.key()) + ", primary=" + U.toShortString(primary) + ", topVer=" + topVer + ']');
}
// Must re-initialize cached entry while holding topology lock.
if (cacheCtx.isNear())
entry.cached(cacheCtx.nearTx().entryExx(entry.key(), topVer));
else if (!cacheCtx.isLocal())
entry.cached(cacheCtx.colocated().entryExx(entry.key(), topVer, true));
else
entry.cached(cacheCtx.local().entryEx(entry.key(), topVer));
if (cacheCtx.isNear() || cacheCtx.isLocal()) {
if (entry.explicitVersion() == null && !remap) {
if (keyLockFut == null) {
keyLockFut = new KeyLockFuture();
add(keyLockFut);
}
keyLockFut.addLockKey(entry.txKey());
}
}
if (cur == null || !cur.primary().id().equals(primary.id()) || (primary.isLocal() && cur.hasNearCacheEntries() != cacheCtx.isNear())) {
boolean clientFirst = cur == null && !topLocked && cctx.kernalContext().clientNode();
cur = new GridDistributedTxMapping(primary);
cur.clientFirst(clientFirst);
}
cur.add(entry);
if (entry.explicitVersion() != null) {
tx.markExplicit(primary.id());
cur.markExplicitLock();
}
entry.nodeId(primary.id());
if (cacheCtx.isNear()) {
while (true) {
try {
GridNearCacheEntry cached = (GridNearCacheEntry) entry.cached();
cached.dhtNodeId(tx.xidVersion(), primary.id());
break;
} catch (GridCacheEntryRemovedException ignore) {
entry.cached(cacheCtx.near().entryEx(entry.key(), topVer));
}
}
}
return cur;
}
use of org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException in project ignite by apache.
the class IgniteTxLocalAdapter method userCommit.
/**
* {@inheritDoc}
*/
@SuppressWarnings({ "CatchGenericClass" })
@Override
public void userCommit() throws IgniteCheckedException {
TransactionState state = state();
if (state != COMMITTING) {
if (remainingTime() == -1)
throw new IgniteTxTimeoutCheckedException("Transaction timed out: " + this);
setRollbackOnly();
throw new IgniteCheckedException("Invalid transaction state for commit [state=" + state + ", tx=" + this + ']');
}
checkValid();
Collection<IgniteTxEntry> commitEntries = (near() || cctx.snapshot().needTxReadLogging()) ? allEntries() : writeEntries();
boolean empty = F.isEmpty(commitEntries);
// locks on backup nodes.
if (!empty || colocated())
cctx.tm().addCommittedTx(this);
if (!empty) {
batchStoreCommit(writeEntries());
WALPointer ptr = null;
cctx.database().checkpointReadLock();
try {
cctx.tm().txContext(this);
AffinityTopologyVersion topVer = topologyVersion();
/*
* Commit to cache. Note that for 'near' transaction we loop through all the entries.
*/
for (IgniteTxEntry txEntry : commitEntries) {
GridCacheContext cacheCtx = txEntry.context();
GridDrType drType = cacheCtx.isDrEnabled() ? DR_PRIMARY : DR_NONE;
UUID nodeId = txEntry.nodeId() == null ? this.nodeId : txEntry.nodeId();
try {
while (true) {
try {
GridCacheEntryEx cached = txEntry.cached();
// transaction manager to make sure locks are held.
if (!evictNearEntry(txEntry, false)) {
if (cacheCtx.isNear() && cacheCtx.dr().receiveEnabled()) {
cached.markObsolete(xidVer);
break;
}
if (cached.detached())
break;
GridCacheEntryEx nearCached = null;
boolean metrics = true;
if (updateNearCache(cacheCtx, txEntry.key(), topVer))
nearCached = cacheCtx.dht().near().peekEx(txEntry.key());
else if (cacheCtx.isNear() && txEntry.locallyMapped())
metrics = false;
boolean evt = !isNearLocallyMapped(txEntry, false);
if (!F.isEmpty(txEntry.entryProcessors()) || !F.isEmpty(txEntry.filters()))
txEntry.cached().unswap(false);
IgniteBiTuple<GridCacheOperation, CacheObject> res = applyTransformClosures(txEntry, true, null);
GridCacheVersion dhtVer = null;
// backup remote transaction completes.
if (cacheCtx.isNear()) {
if (txEntry.op() == CREATE || txEntry.op() == UPDATE || txEntry.op() == DELETE || txEntry.op() == TRANSFORM)
dhtVer = txEntry.dhtVersion();
if ((txEntry.op() == CREATE || txEntry.op() == UPDATE) && txEntry.conflictExpireTime() == CU.EXPIRE_TIME_CALCULATE) {
ExpiryPolicy expiry = cacheCtx.expiryForTxEntry(txEntry);
if (expiry != null) {
txEntry.cached().unswap(false);
Duration duration = cached.hasValue() ? expiry.getExpiryForUpdate() : expiry.getExpiryForCreation();
txEntry.ttl(CU.toTtl(duration));
}
}
}
GridCacheOperation op = res.get1();
CacheObject val = res.get2();
// Deal with conflicts.
GridCacheVersion explicitVer = txEntry.conflictVersion() != null ? txEntry.conflictVersion() : writeVersion();
if ((op == CREATE || op == UPDATE) && txEntry.conflictExpireTime() == CU.EXPIRE_TIME_CALCULATE) {
ExpiryPolicy expiry = cacheCtx.expiryForTxEntry(txEntry);
if (expiry != null) {
Duration duration = cached.hasValue() ? expiry.getExpiryForUpdate() : expiry.getExpiryForCreation();
long ttl = CU.toTtl(duration);
txEntry.ttl(ttl);
if (ttl == CU.TTL_ZERO)
op = DELETE;
}
}
boolean conflictNeedResolve = cacheCtx.conflictNeedResolve();
GridCacheVersionConflictContext<?, ?> conflictCtx = null;
if (conflictNeedResolve) {
IgniteBiTuple<GridCacheOperation, GridCacheVersionConflictContext> conflictRes = conflictResolve(op, txEntry, val, explicitVer, cached);
assert conflictRes != null;
conflictCtx = conflictRes.get2();
if (conflictCtx.isUseOld())
op = NOOP;
else if (conflictCtx.isUseNew()) {
txEntry.ttl(conflictCtx.ttl());
txEntry.conflictExpireTime(conflictCtx.expireTime());
} else {
assert conflictCtx.isMerge();
op = conflictRes.get1();
val = txEntry.context().toCacheObject(conflictCtx.mergeValue());
explicitVer = writeVersion();
txEntry.ttl(conflictCtx.ttl());
txEntry.conflictExpireTime(conflictCtx.expireTime());
}
} else
// Nullify explicit version so that innerSet/innerRemove will work as usual.
explicitVer = null;
if (sndTransformedVals || conflictNeedResolve) {
assert sndTransformedVals && cacheCtx.isReplicated() || conflictNeedResolve;
txEntry.value(val, true, false);
txEntry.op(op);
txEntry.entryProcessors(null);
txEntry.conflictVersion(explicitVer);
}
if (dhtVer == null)
dhtVer = explicitVer != null ? explicitVer : writeVersion();
if (op == CREATE || op == UPDATE) {
assert val != null : txEntry;
GridCacheUpdateTxResult updRes = cached.innerSet(this, eventNodeId(), txEntry.nodeId(), val, false, false, txEntry.ttl(), evt, metrics, txEntry.keepBinary(), txEntry.hasOldValue(), txEntry.oldValue(), topVer, null, cached.detached() ? DR_NONE : drType, txEntry.conflictExpireTime(), cached.isNear() ? null : explicitVer, CU.subjectId(this, cctx), resolveTaskName(), dhtVer, null);
if (updRes.success())
txEntry.updateCounter(updRes.updatePartitionCounter());
if (updRes.loggedPointer() != null)
ptr = updRes.loggedPointer();
if (nearCached != null && updRes.success()) {
nearCached.innerSet(null, eventNodeId(), nodeId, val, false, false, txEntry.ttl(), false, metrics, txEntry.keepBinary(), txEntry.hasOldValue(), txEntry.oldValue(), topVer, CU.empty0(), DR_NONE, txEntry.conflictExpireTime(), null, CU.subjectId(this, cctx), resolveTaskName(), dhtVer, null);
}
} else if (op == DELETE) {
GridCacheUpdateTxResult updRes = cached.innerRemove(this, eventNodeId(), txEntry.nodeId(), false, evt, metrics, txEntry.keepBinary(), txEntry.hasOldValue(), txEntry.oldValue(), topVer, null, cached.detached() ? DR_NONE : drType, cached.isNear() ? null : explicitVer, CU.subjectId(this, cctx), resolveTaskName(), dhtVer, null);
if (updRes.success())
txEntry.updateCounter(updRes.updatePartitionCounter());
if (updRes.loggedPointer() != null)
ptr = updRes.loggedPointer();
if (nearCached != null && updRes.success()) {
nearCached.innerRemove(null, eventNodeId(), nodeId, false, false, metrics, txEntry.keepBinary(), txEntry.hasOldValue(), txEntry.oldValue(), topVer, CU.empty0(), DR_NONE, null, CU.subjectId(this, cctx), resolveTaskName(), dhtVer, null);
}
} else if (op == RELOAD) {
cached.innerReload();
if (nearCached != null)
nearCached.innerReload();
} else if (op == READ) {
CacheGroupContext grp = cacheCtx.group();
if (grp.persistenceEnabled() && grp.walEnabled() && cctx.snapshot().needTxReadLogging()) {
ptr = cctx.wal().log(new DataRecord(new DataEntry(cacheCtx.cacheId(), txEntry.key(), val, op, nearXidVersion(), writeVersion(), 0, txEntry.key().partition(), txEntry.updateCounter())));
}
ExpiryPolicy expiry = cacheCtx.expiryForTxEntry(txEntry);
if (expiry != null) {
Duration duration = expiry.getExpiryForAccess();
if (duration != null)
cached.updateTtl(null, CU.toTtl(duration));
}
if (log.isDebugEnabled())
log.debug("Ignoring READ entry when committing: " + txEntry);
} else {
assert ownsLock(txEntry.cached()) : "Transaction does not own lock for group lock entry during commit [tx=" + this + ", txEntry=" + txEntry + ']';
if (conflictCtx == null || !conflictCtx.isUseOld()) {
if (txEntry.ttl() != CU.TTL_NOT_CHANGED)
cached.updateTtl(null, txEntry.ttl());
}
if (log.isDebugEnabled())
log.debug("Ignoring NOOP entry when committing: " + txEntry);
}
}
// if an entry is obsolete).
if (txEntry.op() != READ)
checkCommitLocks(cached);
// Break out of while loop.
break;
}// If entry cached within transaction got removed.
catch (GridCacheEntryRemovedException ignored) {
if (log.isDebugEnabled())
log.debug("Got removed entry during transaction commit (will retry): " + txEntry);
txEntry.cached(entryEx(cacheCtx, txEntry.txKey(), topologyVersion()));
}
}
} catch (Throwable ex) {
// We are about to initiate transaction rollback when tx has started to committing.
// Need to remove version from committed list.
cctx.tm().removeCommittedTx(this);
if (X.hasCause(ex, GridCacheIndexUpdateException.class) && cacheCtx.cache().isMongoDataCache()) {
if (log.isDebugEnabled())
log.debug("Failed to update mongo document index (transaction entry will " + "be ignored): " + txEntry);
// Set operation to NOOP.
txEntry.op(NOOP);
errorWhenCommitting();
throw ex;
} else {
boolean nodeStopping = X.hasCause(ex, NodeStoppingException.class);
IgniteCheckedException err = new IgniteTxHeuristicCheckedException("Failed to locally write to cache " + "(all transaction entries will be invalidated, however there was a window when " + "entries for this transaction were visible to others): " + this, ex);
if (nodeStopping) {
U.warn(log, "Failed to commit transaction, node is stopping " + "[tx=" + this + ", err=" + ex + ']');
} else
U.error(log, "Heuristic transaction failure.", err);
COMMIT_ERR_UPD.compareAndSet(this, null, err);
state(UNKNOWN);
try {
// Courtesy to minimize damage.
uncommit(nodeStopping);
} catch (Throwable ex1) {
U.error(log, "Failed to uncommit transaction: " + this, ex1);
if (ex1 instanceof Error)
throw ex1;
}
if (ex instanceof Error)
throw ex;
throw err;
}
}
}
if (ptr != null && !cctx.tm().logTxRecords())
cctx.wal().fsync(ptr);
} catch (StorageException e) {
throw new IgniteCheckedException("Failed to log transaction record " + "(transaction will be rolled back): " + this, e);
} finally {
cctx.database().checkpointReadUnlock();
cctx.tm().resetContext();
}
}
// Do not unlock transaction entries if one-phase commit.
if (!onePhaseCommit()) {
if (DONE_FLAG_UPD.compareAndSet(this, 0, 1)) {
// Unlock all locks.
cctx.tm().commitTx(this);
boolean needsCompletedVersions = needsCompletedVersions();
assert !needsCompletedVersions || completedBase != null;
assert !needsCompletedVersions || committedVers != null;
assert !needsCompletedVersions || rolledbackVers != null;
}
}
}
use of org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException in project ignite by apache.
the class IgniteTxLocalAdapter method addEntry.
/**
* @param op Cache operation.
* @param val Value.
* @param expiryPlc Explicitly specified expiry policy.
* @param invokeArgs Optional arguments for EntryProcessor.
* @param entryProcessor Entry processor.
* @param entry Cache entry.
* @param filter Filter.
* @param filtersSet {@code True} if filter should be marked as set.
* @param drTtl DR TTL (if any).
* @param drExpireTime DR expire time (if any).
* @param drVer DR version.
* @param skipStore Skip store flag.
* @return Transaction entry.
*/
protected final IgniteTxEntry addEntry(GridCacheOperation op, @Nullable CacheObject val, @Nullable EntryProcessor entryProcessor, Object[] invokeArgs, GridCacheEntryEx entry, @Nullable ExpiryPolicy expiryPlc, CacheEntryPredicate[] filter, boolean filtersSet, long drTtl, long drExpireTime, @Nullable GridCacheVersion drVer, boolean skipStore, boolean keepBinary, boolean addReader) {
assert invokeArgs == null || op == TRANSFORM;
IgniteTxKey key = entry.txKey();
checkInternal(key);
TransactionState state = state();
assert state == TransactionState.ACTIVE || remainingTime() == -1 : "Invalid tx state for adding entry [op=" + op + ", val=" + val + ", entry=" + entry + ", filter=" + Arrays.toString(filter) + ", txCtx=" + cctx.tm().txContextVersion() + ", tx=" + this + ']';
IgniteTxEntry old = entry(key);
// Keep old filter if already have one (empty filter is always overridden).
if (!filtersSet || !F.isEmptyOrNulls(filter)) {
// Replace filter if previous filter failed.
if (old != null && old.filtersSet())
filter = old.filters();
}
IgniteTxEntry txEntry;
if (old != null) {
if (entryProcessor != null) {
assert val == null;
assert op == TRANSFORM;
// Will change the op.
old.addEntryProcessor(entryProcessor, invokeArgs);
} else {
assert old.op() != TRANSFORM;
old.op(op);
old.value(val, op == CREATE || op == UPDATE || op == DELETE, op == READ);
}
// Keep old ttl value.
old.cached(entry);
old.filters(filter);
// Keep old skipStore and keepBinary flags.
old.skipStore(skipStore);
old.keepBinary(keepBinary);
// Update ttl if specified.
if (drTtl >= 0L) {
assert drExpireTime >= 0L;
entryTtlDr(key, drTtl, drExpireTime);
} else
entryExpiry(key, expiryPlc);
txEntry = old;
if (log.isDebugEnabled())
log.debug("Updated transaction entry: " + txEntry);
} else {
boolean hasDrTtl = drTtl >= 0;
txEntry = new IgniteTxEntry(entry.context(), this, op, val, EntryProcessorResourceInjectorProxy.wrap(cctx.kernalContext(), entryProcessor), invokeArgs, hasDrTtl ? drTtl : -1L, entry, filter, drVer, skipStore, keepBinary, addReader);
txEntry.conflictExpireTime(drExpireTime);
if (!hasDrTtl)
txEntry.expiry(expiryPlc);
txState.addEntry(txEntry);
if (log.isDebugEnabled())
log.debug("Created transaction entry: " + txEntry);
}
txEntry.filtersSet(filtersSet);
while (true) {
try {
updateExplicitVersion(txEntry, entry);
return txEntry;
} catch (GridCacheEntryRemovedException ignore) {
if (log.isDebugEnabled())
log.debug("Got removed entry in transaction newEntry method (will retry): " + entry);
entry = entryEx(entry.context(), txEntry.txKey(), topologyVersion());
txEntry.cached(entry);
}
}
}
use of org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException in project ignite by apache.
the class IgniteTxLocalAdapter method postLockWrite.
/**
* Post lock processing for put or remove.
*
* @param cacheCtx Context.
* @param keys Keys.
* @param ret Return value.
* @param rmv {@code True} if remove.
* @param retval Flag to return value or not.
* @param read {@code True} if read.
* @param accessTtl TTL for read operation.
* @param filter Filter to check entries.
* @throws IgniteCheckedException If error.
* @param computeInvoke If {@code true} computes return value for invoke operation.
*/
@SuppressWarnings("unchecked")
protected final void postLockWrite(GridCacheContext cacheCtx, Iterable<KeyCacheObject> keys, GridCacheReturn ret, boolean rmv, boolean retval, boolean read, long accessTtl, CacheEntryPredicate[] filter, boolean computeInvoke) throws IgniteCheckedException {
for (KeyCacheObject k : keys) {
IgniteTxEntry txEntry = entry(cacheCtx.txKey(k));
if (txEntry == null)
throw new IgniteCheckedException("Transaction entry is null (most likely collection of keys passed into cache " + "operation was changed before operation completed) [missingKey=" + k + ", tx=" + this + ']');
while (true) {
GridCacheEntryEx cached = txEntry.cached();
try {
assert cached.detached() || cached.lockedByThread(threadId) || isRollbackOnly() : "Transaction lock is not acquired [entry=" + cached + ", tx=" + this + ", nodeId=" + cctx.localNodeId() + ", threadId=" + threadId + ']';
if (log.isDebugEnabled())
log.debug("Post lock write entry: " + cached);
CacheObject v = txEntry.previousValue();
boolean hasPrevVal = txEntry.hasPreviousValue();
if (onePhaseCommit())
filter = txEntry.filters();
// If we have user-passed filter, we must read value into entry for peek().
if (!F.isEmptyOrNulls(filter) && !F.isAlwaysTrue(filter))
retval = true;
boolean invoke = txEntry.op() == TRANSFORM;
if (retval || invoke) {
if (!cacheCtx.isNear()) {
if (!hasPrevVal) {
// For non-local cache should read from store after lock on primary.
boolean readThrough = cacheCtx.isLocal() && (invoke || cacheCtx.loadPreviousValue()) && !txEntry.skipStore();
v = cached.innerGet(null, this, readThrough, /*metrics*/
!invoke, /*event*/
!invoke && !dht(), CU.subjectId(this, cctx), null, resolveTaskName(), null, txEntry.keepBinary());
}
} else {
if (!hasPrevVal)
v = cached.rawGet();
}
if (txEntry.op() == TRANSFORM) {
if (computeInvoke) {
GridCacheVersion ver;
try {
ver = cached.version();
} catch (GridCacheEntryRemovedException e) {
assert optimistic() : txEntry;
if (log.isDebugEnabled())
log.debug("Failed to get entry version: [msg=" + e.getMessage() + ']');
ver = null;
}
addInvokeResult(txEntry, v, ret, ver);
}
} else
ret.value(cacheCtx, v, txEntry.keepBinary());
}
boolean pass = F.isEmpty(filter) || cacheCtx.isAll(cached, filter);
// For remove operation we return true only if we are removing s/t,
// i.e. cached value is not null.
ret.success(pass && (!retval ? !rmv || cached.hasValue() || v != null : !rmv || v != null));
if (onePhaseCommit())
txEntry.filtersPassed(pass);
boolean updateTtl = read;
if (pass) {
txEntry.markValid();
if (log.isDebugEnabled())
log.debug("Filter passed in post lock for key: " + k);
} else {
// Revert operation to previous. (if no - NOOP, so entry will be unlocked).
txEntry.setAndMarkValid(txEntry.previousOperation(), cacheCtx.toCacheObject(ret.value()));
txEntry.filters(CU.empty0());
txEntry.filtersSet(false);
updateTtl = !cacheCtx.putIfAbsentFilter(filter);
}
if (updateTtl) {
if (!read) {
ExpiryPolicy expiryPlc = cacheCtx.expiryForTxEntry(txEntry);
if (expiryPlc != null)
txEntry.ttl(CU.toTtl(expiryPlc.getExpiryForAccess()));
} else
txEntry.ttl(accessTtl);
}
// While.
break;
}// If entry cached within transaction got removed before lock.
catch (GridCacheEntryRemovedException ignore) {
if (log.isDebugEnabled())
log.debug("Got removed entry in putAllAsync method (will retry): " + cached);
txEntry.cached(entryEx(cached.context(), txEntry.txKey(), topologyVersion()));
}
}
}
}
Aggregations