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