/** * @param fut Future to remove. * @return {@code True} if removed. */ @SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter"}) public boolean removeFuture(GridCacheFuture<?> fut) { if (!fut.trackable()) return true; Collection<GridCacheFuture<?>> cur = futs.get(fut.version()); if (cur == null) return false; boolean rmv, empty; synchronized (cur) { rmv = cur.remove(fut); empty = cur.isEmpty(); } if (rmv) { if (log.isDebugEnabled()) log.debug("Removed future from future map: " + fut); } else if (log.isDebugEnabled()) log.debug( "Attempted to remove a non-registered future (has it been already removed?): " + fut); if (empty && futs.remove(fut.version(), cur)) if (log.isDebugEnabled()) log.debug("Removed future list from futures map for lock version: " + fut.version()); return rmv; }
/** {@inheritDoc} */ @SuppressWarnings({"unchecked"}) @Override public void onOwnerChanged( GridCacheEntryEx entry, GridCacheMvccCandidate prev, GridCacheMvccCandidate owner) { assert entry != null; assert owner != prev : "New and previous owner are identical instances: " + owner; assert owner == null || prev == null || !owner.version().equals(prev.version()) : "New and previous owners have identical versions [owner=" + owner + ", prev=" + prev + ']'; if (log.isDebugEnabled()) log.debug( "Received owner changed callback [" + entry.key() + ", owner=" + owner + ", prev=" + prev + ']'); if (owner != null && (owner.local() || owner.nearLocal())) { Collection<? extends GridCacheFuture> futCol = futs.get(owner.version()); if (futCol != null) { for (GridCacheFuture fut : futCol) { if (fut instanceof GridCacheMvccFuture && !fut.isDone()) { GridCacheMvccFuture<Boolean> mvccFut = (GridCacheMvccFuture<Boolean>) fut; // Since this method is called outside of entry synchronization, // we can safely invoke any method on the future. // Also note that we don't remove future here if it is done. // The removal is initiated from within future itself. if (mvccFut.onOwnerChanged(entry, owner)) return; } } } } if (log.isDebugEnabled()) log.debug( "Lock future not found for owner change callback (will try transaction futures) [owner=" + owner + ", prev=" + prev + ", entry=" + entry + ']'); // If no future was found, delegate to transaction manager. if (cctx.tm().onOwnerChanged(entry, owner)) { if (log.isDebugEnabled()) log.debug("Found transaction for changed owner: " + owner); } else if (log.isDebugEnabled()) log.debug("Failed to find transaction for changed owner: " + owner); for (FinishLockFuture f : finishFuts) f.recheck(entry); }
/** * Gets future for given future ID and lock ID. * * @param ver Lock ID. * @param futId Future ID. * @return Future. */ @SuppressWarnings({"unchecked"}) @Nullable public GridCacheFuture future(GridCacheVersion ver, IgniteUuid futId) { Collection<? extends GridCacheFuture> futs = this.futs.get(ver); if (futs != null) for (GridCacheFuture<?> fut : futs) if (fut.futureId().equals(futId)) { if (log.isDebugEnabled()) log.debug("Found future in futures map: " + fut); return fut; } if (log.isDebugEnabled()) log.debug("Failed to find future in futures map [ver=" + ver + ", futId=" + futId + ']'); return null; }
@Override public void onEvent(Event evt) { assert evt instanceof DiscoveryEvent; assert evt.type() == EVT_NODE_FAILED || evt.type() == EVT_NODE_LEFT; DiscoveryEvent discoEvt = (DiscoveryEvent) evt; if (log.isDebugEnabled()) log.debug("Processing node left [nodeId=" + discoEvt.eventNode().id() + "]"); for (Collection<GridCacheFuture<?>> futsCol : futs.values()) { for (GridCacheFuture<?> fut : futsCol) { if (!fut.trackable()) { if (log.isDebugEnabled()) log.debug("Skipping non-trackable future: " + fut); continue; } fut.onNodeLeft(discoEvt.eventNode().id()); if (fut.isCancelled() || fut.isDone()) removeFuture(fut); } } for (IgniteInternalFuture<?> fut : atomicFuts.values()) { if (fut instanceof GridCacheFuture) { GridCacheFuture cacheFut = (GridCacheFuture) fut; cacheFut.onNodeLeft(discoEvt.eventNode().id()); if (cacheFut.isCancelled() || cacheFut.isDone()) { GridCacheVersion futVer = cacheFut.version(); if (futVer != null) atomicFuts.remove(futVer, fut); } } } }
/** * Adds future. * * @param fut Future. * @return {@code True} if added. */ @SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter"}) public boolean addFuture(final GridCacheFuture<?> fut) { if (fut.isDone()) { fut.markNotTrackable(); return true; } if (!fut.trackable()) return true; while (true) { Collection<GridCacheFuture<?>> old = futs.putIfAbsent( fut.version(), new ConcurrentLinkedDeque8<GridCacheFuture<?>>() { /** */ private int hash; { // Make sure that we add future to queue before // adding queue to the map of futures. add(fut); } @Override public int hashCode() { if (hash == 0) hash = System.identityHashCode(this); return hash; } @Override public boolean equals(Object obj) { return obj == this; } }); if (old != null) { boolean empty, dup = false; synchronized (old) { empty = old.isEmpty(); if (!empty) dup = old.contains(fut); if (!empty && !dup) old.add(fut); } // Future is being removed, so we force-remove here and try again. if (empty) { if (futs.remove(fut.version(), old)) { if (log.isDebugEnabled()) log.debug("Removed future list from futures map for lock version: " + fut.version()); } continue; } if (dup) { if (log.isDebugEnabled()) log.debug("Found duplicate future in futures map (will not add): " + fut); return false; } } // Handle version mappings. if (fut instanceof GridCacheMappedVersion) { GridCacheVersion from = ((GridCacheMappedVersion) fut).mappedVersion(); if (from != null) mapVersion(from, fut.version()); } if (log.isDebugEnabled()) log.debug("Added future to future map: " + fut); break; } // Close window in case of node is gone before the future got added to // the map of futures. for (ClusterNode n : fut.nodes()) { if (cctx.discovery().node(n.id()) == null) fut.onNodeLeft(n.id()); } // Just in case if future was completed before it was added. if (fut.isDone()) removeFuture(fut); else onFutureAdded(fut); return true; }