use of org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate in project ignite by apache.
the class GridLocalCacheEntry method removeLock.
/**
* {@inheritDoc}
*/
@Override
public boolean removeLock(GridCacheVersion ver) throws GridCacheEntryRemovedException {
CacheObject val;
CacheLockCandidates prev = null;
CacheLockCandidates owner = null;
GridCacheMvccCandidate doomed;
GridCacheVersion deferredDelVer;
lockEntry();
try {
GridCacheVersion obsoleteVer = obsoleteVersionExtras();
if (obsoleteVer != null && !obsoleteVer.equals(ver))
checkObsolete();
GridCacheMvcc mvcc = mvccExtras();
doomed = mvcc == null ? null : mvcc.candidate(ver);
if (doomed != null) {
prev = mvcc.allOwners();
mvcc.remove(ver);
if (mvcc.isEmpty())
mvccExtras(null);
else
owner = mvcc.allOwners();
}
val = this.val;
deferredDelVer = this.ver;
} finally {
unlockEntry();
}
if (val == null) {
boolean deferred = cctx.deferredDelete() && !detached() && !isInternal();
if (deferred) {
if (deferredDelVer != null)
cctx.onDeferredDelete(this, deferredDelVer);
}
}
if (doomed != null)
checkThreadChain(doomed);
checkOwnerChanged(prev, owner, val);
return doomed != null;
}
use of org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate in project ignite by apache.
the class GridNearLockFuture method map.
/**
* Maps keys to nodes. Note that we can not simply group keys by nodes and send lock request as
* such approach does not preserve order of lock acquisition. Instead, keys are split in continuous
* groups belonging to one primary node and locks for these groups are acquired sequentially.
*
* @param keys Keys.
* @param remap Remap flag.
* @param topLocked {@code True} if thread already acquired lock preventing topology change.
*/
private void map(Iterable<KeyCacheObject> keys, boolean remap, boolean topLocked) {
try {
AffinityTopologyVersion topVer = this.topVer;
assert topVer != null;
assert topVer.topologyVersion() > 0 : topVer;
if (CU.affinityNodes(cctx, topVer).isEmpty()) {
onDone(new ClusterTopologyServerNotFoundException("Failed to map keys for near-only cache (all " + "partition nodes left the grid)."));
return;
}
boolean clientNode = cctx.kernalContext().clientNode();
assert !remap || (clientNode && (tx == null || !tx.hasRemoteLocks()));
synchronized (this) {
mappings = new ArrayDeque<>();
// Assign keys to primary nodes.
GridNearLockMapping map = null;
for (KeyCacheObject key : keys) {
GridNearLockMapping updated = map(key, map, topVer);
// If new mapping was created, add to collection.
if (updated != map) {
mappings.add(updated);
if (tx != null && updated.node().isLocal())
tx.nearLocallyMapped(true);
}
map = updated;
}
if (isDone()) {
if (log.isDebugEnabled())
log.debug("Abandoning (re)map because future is done: " + this);
return;
}
if (log.isDebugEnabled())
log.debug("Starting (re)map for mappings [mappings=" + mappings + ", fut=" + this + ']');
boolean first = true;
// Create mini futures.
for (Iterator<GridNearLockMapping> iter = mappings.iterator(); iter.hasNext(); ) {
GridNearLockMapping mapping = iter.next();
ClusterNode node = mapping.node();
Collection<KeyCacheObject> mappedKeys = mapping.mappedKeys();
assert !mappedKeys.isEmpty();
GridNearLockRequest req = null;
Collection<KeyCacheObject> distributedKeys = new ArrayList<>(mappedKeys.size());
boolean explicit = false;
for (KeyCacheObject key : mappedKeys) {
IgniteTxKey txKey = cctx.txKey(key);
while (true) {
GridNearCacheEntry entry = null;
try {
entry = cctx.near().entryExx(key, topVer);
if (!cctx.isAll(entry, filter)) {
if (log.isDebugEnabled())
log.debug("Entry being locked did not pass filter (will not lock): " + entry);
onComplete(false, false);
return;
}
// Removed exception may be thrown here.
GridCacheMvccCandidate cand = addEntry(topVer, entry, node.id());
if (isDone()) {
if (log.isDebugEnabled())
log.debug("Abandoning (re)map because future is done after addEntry attempt " + "[fut=" + this + ", entry=" + entry + ']');
return;
}
if (cand != null) {
if (tx == null && !cand.reentry())
cctx.mvcc().addExplicitLock(threadId, cand, topVer);
IgniteBiTuple<GridCacheVersion, CacheObject> val = entry.versionedValue();
if (val == null) {
GridDhtCacheEntry dhtEntry = dht().peekExx(key);
try {
if (dhtEntry != null)
val = dhtEntry.versionedValue(topVer);
} catch (GridCacheEntryRemovedException ignored) {
assert dhtEntry.obsolete() : dhtEntry;
if (log.isDebugEnabled())
log.debug("Got removed exception for DHT entry in map (will ignore): " + dhtEntry);
}
}
GridCacheVersion dhtVer = null;
if (val != null) {
dhtVer = val.get1();
valMap.put(key, val);
}
if (!cand.reentry()) {
if (req == null) {
boolean clientFirst = false;
if (first) {
clientFirst = clientNode && !topLocked && (tx == null || !tx.hasRemoteLocks());
first = false;
}
assert !implicitTx() && !implicitSingleTx() : tx;
req = new GridNearLockRequest(cctx.cacheId(), topVer, cctx.nodeId(), threadId, futId, lockVer, inTx(), read, retval, isolation(), isInvalidate(), timeout, mappedKeys.size(), inTx() ? tx.size() : mappedKeys.size(), inTx() && tx.syncMode() == FULL_SYNC, inTx() ? tx.taskNameHash() : 0, read ? createTtl : -1L, read ? accessTtl : -1L, skipStore, keepBinary, clientFirst, true, cctx.deploymentEnabled(), inTx() ? tx.label() : null);
mapping.request(req);
}
distributedKeys.add(key);
if (tx != null)
tx.addKeyMapping(txKey, mapping.node());
req.addKeyBytes(key, retval && dhtVer == null, dhtVer, // Include DHT version to match remote DHT entry.
cctx);
}
if (cand.reentry())
explicit = tx != null && !entry.hasLockCandidate(tx.xidVersion());
} else {
if (timedOut)
return;
// Ignore reentries within transactions.
explicit = tx != null && !entry.hasLockCandidate(tx.xidVersion());
}
if (explicit)
tx.addKeyMapping(txKey, mapping.node());
break;
} catch (GridCacheEntryRemovedException ignored) {
assert entry.obsolete() : "Got removed exception on non-obsolete entry: " + entry;
if (log.isDebugEnabled())
log.debug("Got removed entry in lockAsync(..) method (will retry): " + entry);
}
}
// Mark mapping explicit lock flag.
if (explicit) {
boolean marked = tx != null && tx.markExplicit(node.id());
assert tx == null || marked;
}
}
if (!distributedKeys.isEmpty())
mapping.distributedKeys(distributedKeys);
else {
assert mapping.request() == null;
iter.remove();
}
}
}
cctx.mvcc().recheckPendingLocks();
proceedMapping();
} catch (IgniteCheckedException ex) {
onError(ex);
}
}
use of org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate in project ignite by apache.
the class GridNearTransactionalCache method removeLocks.
/**
* Removes locks regardless of whether they are owned or not for given
* version and keys.
*
* @param ver Lock version.
* @param keys Keys.
*/
public void removeLocks(GridCacheVersion ver, Collection<KeyCacheObject> keys) {
if (keys.isEmpty())
return;
try {
int keyCnt = -1;
Map<ClusterNode, GridNearUnlockRequest> map = null;
for (KeyCacheObject key : keys) {
// Send request to remove from remote nodes.
GridNearUnlockRequest req = null;
while (true) {
GridDistributedCacheEntry entry = peekExx(key);
try {
if (entry != null) {
GridCacheMvccCandidate cand = entry.candidate(ver);
if (cand != null) {
if (map == null) {
Collection<ClusterNode> affNodes = CU.affinityNodes(ctx, cand.topologyVersion());
if (F.isEmpty(affNodes))
return;
keyCnt = (int) Math.ceil((double) keys.size() / affNodes.size());
map = U.newHashMap(affNodes.size());
}
ClusterNode primary = ctx.affinity().primaryByKey(key, cand.topologyVersion());
if (primary == null) {
if (log.isDebugEnabled())
log.debug("Failed to unlock key (all partition nodes left the grid).");
break;
}
if (!primary.isLocal()) {
req = map.get(primary);
if (req == null) {
map.put(primary, req = new GridNearUnlockRequest(ctx.cacheId(), keyCnt, ctx.deploymentEnabled()));
req.version(ver);
}
}
// Remove candidate from local node first.
if (entry.removeLock(cand.version())) {
if (primary.isLocal()) {
dht.removeLocks(primary.id(), ver, F.asList(key), true);
assert req == null;
continue;
}
req.addKey(entry.key(), ctx);
}
}
}
break;
} catch (GridCacheEntryRemovedException ignored) {
if (log.isDebugEnabled())
log.debug("Attempted to remove lock from removed entry (will retry) [rmvVer=" + ver + ", entry=" + entry + ']');
}
}
}
if (map == null || map.isEmpty())
return;
IgnitePair<Collection<GridCacheVersion>> versPair = ctx.tm().versions(ver);
Collection<GridCacheVersion> committed = versPair.get1();
Collection<GridCacheVersion> rolledback = versPair.get2();
for (Map.Entry<ClusterNode, GridNearUnlockRequest> mapping : map.entrySet()) {
ClusterNode n = mapping.getKey();
GridDistributedUnlockRequest req = mapping.getValue();
if (!F.isEmpty(req.keys())) {
req.completedVersions(committed, rolledback);
// We don't wait for reply to this message.
ctx.io().send(n, req, ctx.ioPolicy());
}
}
} catch (IgniteCheckedException ex) {
U.error(log, "Failed to unlock the lock for keys: " + keys, ex);
}
}
use of org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate in project ignite by apache.
the class GridNearCacheEntry method dhtNodeId.
/**
* @param ver Version to set DHT node ID for.
* @param dhtNodeId DHT node ID.
* @return {@code true} if candidate was found.
* @throws GridCacheEntryRemovedException If entry is removed.
*/
@Nullable
public GridCacheMvccCandidate dhtNodeId(GridCacheVersion ver, UUID dhtNodeId) throws GridCacheEntryRemovedException {
lockEntry();
try {
checkObsolete();
GridCacheMvcc mvcc = mvccExtras();
GridCacheMvccCandidate cand = mvcc == null ? null : mvcc.candidate(ver);
if (cand == null)
return null;
cand.otherNodeId(dhtNodeId);
return cand;
} finally {
unlockEntry();
}
}
use of org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate in project ignite by apache.
the class GridNearCacheEntry method addNearLocal.
/**
* Add near local candidate.
*
* @param dhtNodeId DHT node ID.
* @param threadId Owning thread ID.
* @param ver Lock version.
* @param topVer Topology version.
* @param timeout Timeout to acquire lock.
* @param reenter Reentry flag.
* @param tx Transaction flag.
* @param implicitSingle Implicit flag.
* @param read Read lock flag.
* @return New candidate.
* @throws GridCacheEntryRemovedException If entry has been removed.
*/
@Nullable
GridCacheMvccCandidate addNearLocal(@Nullable UUID dhtNodeId, long threadId, GridCacheVersion ver, AffinityTopologyVersion topVer, long timeout, boolean reenter, boolean tx, boolean implicitSingle, boolean read) throws GridCacheEntryRemovedException {
CacheLockCandidates prev;
CacheLockCandidates owner = null;
GridCacheMvccCandidate cand;
CacheObject val;
UUID locId = cctx.nodeId();
lockEntry();
try {
checkObsolete();
GridCacheMvcc mvcc = mvccExtras();
if (mvcc == null) {
mvcc = new GridCacheMvcc(cctx);
mvccExtras(mvcc);
}
GridCacheMvccCandidate c = mvcc.localCandidateByThreadOrVer(locId, threadId, ver);
if (c != null)
return reenter ? c.reenter() : null;
prev = mvcc.allOwners();
boolean emptyBefore = mvcc.isEmpty();
// Lock could not be acquired.
if (timeout < 0 && !emptyBefore)
return null;
// Local lock for near cache is a local lock.
cand = mvcc.addNearLocal(this, locId, dhtNodeId, threadId, ver, tx, implicitSingle, read);
cand.topologyVersion(topVer);
boolean emptyAfter = mvcc.isEmpty();
checkCallbacks(emptyBefore, emptyAfter);
val = this.val;
if (emptyAfter)
mvccExtras(null);
else
owner = mvcc.allOwners();
} finally {
unlockEntry();
}
// This call must be outside of synchronization.
checkOwnerChanged(prev, owner, val);
return cand;
}
Aggregations