/** * @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; }
@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; }