/** * @param newEntries Infos. * @param lsnr Listener for the operation future. * @throws GridInterruptedException If failed. * @return Future for operation. */ @Nullable GridFutureAdapter<?> update( Iterable<Map.Entry<K, V>> newEntries, GridInClosure<GridFuture<?>> lsnr) throws GridInterruptedException { List<Map.Entry<K, V>> entries0 = null; GridFutureAdapter<Object> curFut0; synchronized (this) { curFut0 = curFut; curFut0.listenAsync(lsnr); for (Map.Entry<K, V> entry : newEntries) entries.add(entry); if (entries.size() >= bufSize) { entries0 = entries; entries = newEntries(); curFut = new GridFutureAdapter<>(ctx); curFut.listenAsync(signalC); } } if (entries0 != null) { submit(entries0, curFut0); if (cancelled) curFut0.onDone( new GridException("Data loader has been cancelled: " + GridDataLoaderImpl.this)); } return curFut0; }
void cancelAll() { GridException err = new GridException("Data loader has been cancelled: " + GridDataLoaderImpl.this); for (GridFuture<?> f : locFuts) { try { f.cancel(); } catch (GridException e) { U.error(log, "Failed to cancel mini-future.", e); } } for (GridFutureAdapter<?> f : reqs.values()) f.onDone(err); }
/** * @param cancel {@code True} to close with cancellation. * @throws GridException If failed. */ @Override public void close(boolean cancel) throws GridException { if (!closed.compareAndSet(false, true)) return; busyLock.block(); if (log.isDebugEnabled()) log.debug("Closing data loader [ldr=" + this + ", cancel=" + cancel + ']'); GridException e = null; try { // Assuming that no methods are called on this loader after this method is called. if (cancel) { cancelled = true; for (Buffer buf : bufMappings.values()) buf.cancelAll(); } else doFlush(); ctx.event().removeLocalEventListener(discoLsnr); ctx.io().removeMessageListener(topic); } catch (GridException e0) { e = e0; } fut.onDone(null, e); if (e != null) throw e; }
void onNodeLeft() { assert !isLocNode; assert bufMappings.get(node.id()) != this; if (log.isDebugEnabled()) log.debug("Forcibly completing futures (node has left): " + node.id()); Exception e = new GridTopologyException( "Failed to wait for request completion " + "(node has left): " + node.id()); for (GridFutureAdapter<Object> f : reqs.values()) f.onDone(e); // Make sure to complete current future. GridFutureAdapter<Object> curFut0; synchronized (this) { curFut0 = curFut; } curFut0.onDone(e); }
/** @param res Response. */ void onResponse(GridDataLoadResponse res) { if (log.isDebugEnabled()) log.debug("Received data load response: " + res); GridFutureAdapter<?> f = reqs.remove(res.requestId()); if (f == null) { if (log.isDebugEnabled()) log.debug("Future for request has not been found: " + res.requestId()); return; } Throwable err = null; byte[] errBytes = res.errorBytes(); if (errBytes != null) { try { GridPeerDeployAware jobPda0 = jobPda; err = ctx.config() .getMarshaller() .unmarshal( errBytes, jobPda0 != null ? jobPda0.classLoader() : U.gridClassLoader()); } catch (GridException e) { f.onDone(null, new GridException("Failed to unmarshal response.", e)); return; } } f.onDone(null, err); if (log.isDebugEnabled()) log.debug( "Finished future [fut=" + f + ", reqId=" + res.requestId() + ", err=" + err + ']'); }
/** {@inheritDoc} */ @Override public GridFuture<?> addData(Collection<? extends Map.Entry<K, V>> entries) { A.notEmpty(entries, "entries"); enterBusy(); try { GridFutureAdapter<Object> resFut = new GridFutureAdapter<>(ctx); activeFuts.add(resFut); resFut.listenAsync(rmvActiveFut); Collection<K> keys = new GridConcurrentHashSet<>(entries.size(), 1.0f, 16); for (Map.Entry<K, V> entry : entries) keys.add(entry.getKey()); load0(entries, resFut, keys, 0); return resFut; } finally { leaveBusy(); } }
/** @param node Node. */ Buffer(GridNode node) { assert node != null; this.node = node; locFuts = new GridConcurrentHashSet<>(); reqs = new ConcurrentHashMap8<>(); // Cache local node flag. isLocNode = node.equals(ctx.discovery().localNode()); entries = newEntries(); curFut = new GridFutureAdapter<>(ctx); curFut.listenAsync(signalC); sem = new Semaphore(parallelOps); }
/** * @return Future if any submitted. * @throws GridInterruptedException If thread has been interrupted. */ @Nullable GridFuture<?> flush() throws GridInterruptedException { List<Map.Entry<K, V>> entries0 = null; GridFutureAdapter<Object> curFut0 = null; synchronized (this) { if (!entries.isEmpty()) { entries0 = entries; curFut0 = curFut; entries = newEntries(); curFut = new GridFutureAdapter<>(ctx); curFut.listenAsync(signalC); } } if (entries0 != null) submit(entries0, curFut0); // Create compound future for this flush. GridCompoundFuture<Object, Object> res = null; for (GridFuture<Object> f : locFuts) { if (res == null) res = new GridCompoundFuture<>(ctx); res.add(f); } for (GridFuture<Object> f : reqs.values()) { if (res == null) res = new GridCompoundFuture<>(ctx); res.add(f); } if (res != null) res.markInitialized(); return res; }
/** @return {@code true} If the loader is closed. */ boolean isClosed() { return fut.isDone(); }
/** * @param entries Entries. * @param resFut Result future. * @param activeKeys Active keys. * @param remaps Remaps count. */ private void load0( Collection<? extends Map.Entry<K, V>> entries, final GridFutureAdapter<Object> resFut, final Collection<K> activeKeys, final int remaps) { assert entries != null; if (remaps >= MAX_REMAP_CNT) { resFut.onDone(new GridException("Failed to finish operation (too many remaps): " + remaps)); return; } Map<GridNode, Collection<Map.Entry<K, V>>> mappings = new HashMap<>(); boolean initPda = ctx.deploy().enabled() && jobPda == null; for (Map.Entry<K, V> entry : entries) { GridNode node; try { K key = entry.getKey(); assert key != null; if (initPda) { jobPda = new DataLoaderPda(key, entry.getValue(), updater); initPda = false; } node = ctx.affinity().mapKeyToNode(cacheName, key); } catch (GridException e) { resFut.onDone(e); return; } if (node == null) { resFut.onDone( new GridTopologyException( "Failed to map key to node " + "(no nodes with cache found in topology) [infos=" + entries.size() + ", cacheName=" + cacheName + ']')); return; } Collection<Map.Entry<K, V>> col = mappings.get(node); if (col == null) mappings.put(node, col = new ArrayList<>()); col.add(entry); } for (final Map.Entry<GridNode, Collection<Map.Entry<K, V>>> e : mappings.entrySet()) { final UUID nodeId = e.getKey().id(); Buffer buf = bufMappings.get(nodeId); if (buf == null) { Buffer old = bufMappings.putIfAbsent(nodeId, buf = new Buffer(e.getKey())); if (old != null) buf = old; } final Collection<Map.Entry<K, V>> entriesForNode = e.getValue(); GridInClosure<GridFuture<?>> lsnr = new GridInClosure<GridFuture<?>>() { @Override public void apply(GridFuture<?> t) { try { t.get(); for (Map.Entry<K, V> e : entriesForNode) activeKeys.remove(e.getKey()); if (activeKeys.isEmpty()) resFut.onDone(); } catch (GridException e1) { if (log.isDebugEnabled()) log.debug("Future finished with error [nodeId=" + nodeId + ", err=" + e1 + ']'); if (cancelled) { resFut.onDone( new GridException( "Data loader has been cancelled: " + GridDataLoaderImpl.this, e1)); } else load0(entriesForNode, resFut, activeKeys, remaps + 1); } } }; GridFutureAdapter<?> f; try { f = buf.update(entriesForNode, lsnr); } catch (GridInterruptedException e1) { resFut.onDone(e1); return; } if (ctx.discovery().node(nodeId) == null) { if (bufMappings.remove(nodeId, buf)) buf.onNodeLeft(); if (f != null) f.onDone( new GridTopologyException( "Failed to wait for request completion " + "(node has left): " + nodeId)); } } }