/// <summary> /// Constructor. /// </summary> /// <param name="target">Target.</param> /// <param name="marsh">Marshaller.</param> /// <param name="cacheName">Cache name.</param> /// <param name="keepBinary">Binary flag.</param> public DataStreamerImpl(IPlatformTargetInternal target, Marshaller marsh, string cacheName, bool keepBinary) : base(target) { _cacheName = cacheName; _keepBinary = keepBinary; // Create empty batch. _batch = new DataStreamerBatch <TK, TV>(); // Allocate GC handle so that this data streamer could be easily dereferenced from native code. WeakReference thisRef = new WeakReference(this); _hnd = marsh.Ignite.HandleRegistry.Allocate(thisRef); // Start topology listening. This call will ensure that buffer size member is updated. DoOutInOp(OpListenTopology, _hnd); // Membar to ensure fields initialization before leaving constructor. Thread.MemoryBarrier(); // Start flusher after everything else is initialized. _flusher = new Flusher <TK, TV>(thisRef); _flusher.RunThread(); }
/// <summary> /// Constructor. /// </summary> /// <param name="prev">Previous batch.</param> public DataStreamerBatch(DataStreamerBatch <TK, TV> prev) { _prev = prev; if (prev != null) { Thread.MemoryBarrier(); // Prevent "prev" field escape. } _fut.Task.ContWith(x => ParentsCompleted()); }
/** <inheritDoc /> */ public void TryFlush() { ThrowIfDisposed(); DataStreamerBatch <TK, TV> batch0 = _batch; if (batch0 != null) { Flush0(batch0, false, PlcFlush); } }
/** <inheritDoc /> */ public void Flush() { ThrowIfDisposed(); DataStreamerBatch <TK, TV> batch0 = _batch; if (batch0 != null) { Flush0(batch0, true, PlcFlush); } else { // Batch is null, i.e. data streamer is closing. Wait for close to complete. _closedEvt.Wait(); } }
/** <inheritDoc /> */ public void Close(bool cancel) { _flusher.Stop(); while (true) { DataStreamerBatch <TK, TV> batch0 = _batch; if (batch0 == null) { // Wait for concurrent close to finish. _closeFut.Task.Wait(); return; } _rwLock.EnterWriteLock(); try { if (!Flush0(batch0, true, cancel ? PlcCancelClose : PlcClose)) { // Retry flushing. continue; } base.Dispose(true); ReleaseHandles(); ThreadPool.QueueUserWorkItem(_ => _closeFut.TrySetResult(null)); return; } catch (Exception e) { base.Dispose(true); ReleaseHandles(); ThreadPool.QueueUserWorkItem(_ => _closeFut.TrySetException(e)); throw; } finally { _rwLock.ExitWriteLock(); } } }
/// <summary> /// Checck whether all previous batches are completed. /// </summary> /// <returns></returns> private bool ParentsCompleted() { DataStreamerBatch <TK, TV> prev0 = _prev; if (prev0 != null) { if (prev0.ParentsCompleted()) { _prev = null; } else { return(false); } } return(_fut.Task.IsCompleted); }
/// <summary> /// Internal flush routine. /// </summary> /// <param name="curBatch"></param> /// <param name="wait">Whether to wait for flush to complete.</param> /// <param name="plc">Whether this is the last batch.</param> /// <returns>Whether this call was able to CAS previous batch</returns> private bool Flush0(DataStreamerBatch <TK, TV> curBatch, bool wait, int plc) { // 1. Try setting new current batch to help further adders. bool res = Interlocked.CompareExchange(ref _batch, (plc == PlcContinue || plc == PlcFlush) ? new DataStreamerBatch <TK, TV>(curBatch) : null, curBatch) == curBatch; // 2. Perform actual send. curBatch.Send(this, plc); if (wait) { // 3. Wait for all futures to finish. curBatch.AwaitCompletion(); } return(res); }
public void AwaitCompletion() { DataStreamerBatch <TK, TV> curBatch = this; while (curBatch != null) { try { curBatch._fut.Get(); } catch (Exception) { // Ignore. } curBatch = curBatch._prev; } }
/** <inheritDoc /> */ public void Close(bool cancel) { _flusher.Stop(); while (true) { DataStreamerBatch <TK, TV> batch0 = _batch; if (batch0 == null) { // Wait for concurrent close to finish. _closedEvt.Wait(); return; } if (Flush0(batch0, true, cancel ? PlcCancelClose : PlcClose)) { _closeFut.OnDone(null, null); _rwLock.EnterWriteLock(); try { base.Dispose(true); if (_rcv != null) { Marshaller.Ignite.HandleRegistry.Release(_rcvHnd); } _closedEvt.Set(); } finally { _rwLock.ExitWriteLock(); } Marshaller.Ignite.HandleRegistry.Release(_hnd); break; } } }
public void AwaitCompletion() { DataStreamerBatch <TK, TV> curBatch = this; while (curBatch != null) { try { curBatch._fut.Get(); } // ReSharper disable once EmptyGeneralCatchClause catch (Exception) { // Ignore. } curBatch = curBatch._prev; } }
/// <summary> /// Internal send routine. /// </summary> /// <param name="ldr">streamer.</param> /// <param name="plc">Policy.</param> public void Send(DataStreamerImpl <TK, TV> ldr, int plc) { // 1. Delegate to the previous batch first. DataStreamerBatch <TK, TV> prev0 = _prev; if (prev0 != null) { prev0.Send(ldr, DataStreamerImpl <TK, TV> .PlcContinue); } // 2. Set guard. _rwLock.EnterWriteLock(); try { if (_sndGuard) { return; } else { _sndGuard = true; } } finally { _rwLock.ExitWriteLock(); } var handleRegistry = ldr.Marshaller.Ignite.HandleRegistry; long futHnd = 0; // 3. Actual send. try { ldr.Update(writer => { writer.WriteInt(plc); if (plc != DataStreamerImpl <TK, TV> .PlcCancelClose) { futHnd = handleRegistry.Allocate(_fut); writer.WriteLong(futHnd); WriteTo(writer); } }); } catch (Exception) { if (futHnd != 0) { handleRegistry.Release(futHnd); } throw; } if (plc == DataStreamerImpl <TK, TV> .PlcCancelClose || _size == 0) { ThreadPool.QueueUserWorkItem(_ => _fut.OnNullResult()); handleRegistry.Release(futHnd); } }