internal FdbFutureSingle([NotNull] FutureHandle handle, [NotNull] Func <FutureHandle, T> selector, CancellationToken ct) { Contract.NotNull(handle, nameof(handle)); Contract.NotNull(selector, nameof(selector)); m_handle = handle; m_resultSelector = selector; try { if (handle.IsInvalid) { // it's dead, Jim ! SetFlag(FdbFuture.Flags.COMPLETED); m_resultSelector = null; return; } if (FdbNative.FutureIsReady(handle)) { // either got a value or an error #if DEBUG_FUTURES Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " was already ready"); #endif HandleCompletion(fromCallback: false); #if DEBUG_FUTURES Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " completed inline"); #endif return; } // register for cancellation (if needed) if (ct.CanBeCanceled) { if (ct.IsCancellationRequested) { // we have already been cancelled #if DEBUG_FUTURES Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " will complete later"); #endif // Abort the future and simulate a Canceled task SetFlag(FdbFuture.Flags.COMPLETED); // note: we don't need to call fdb_future_cancel because fdb_future_destroy will take care of everything handle.Dispose(); // also, don't keep a reference on the callback because it won't be needed m_resultSelector = null; this.TrySetCanceled(); return; } // token still active RegisterForCancellation(ct); } #if DEBUG_FUTURES Debug.WriteLine("Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " will complete later"); #endif TrySetFlag(FdbFuture.Flags.READY); // add this instance to the list of pending futures var prm = RegisterCallback(this); // register the callback handler var err = FdbNative.FutureSetCallback(handle, CallbackHandler, prm); if (Fdb.Failed(err)) { // uhoh #if DEBUG_FUTURES Debug.WriteLine("Failed to set callback for Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " !!!"); #endif throw Fdb.MapToException(err); } } catch { // this is bad news, since we are in the constructor, we need to clear everything SetFlag(FdbFuture.Flags.DISPOSED); UnregisterCancellationRegistration(); UnregisterCallback(this); // kill the future handle m_handle.Dispose(); // this is technically not needed, but just to be safe... this.TrySetCanceled(); throw; } GC.KeepAlive(this); }
protected override void CloseHandles() { m_handle?.Dispose(); }