Esempio n. 1
0
 protected override void Destroy(IntPtr handle)
 {
     FdbNative.ClusterDestroy(handle);
     Interlocked.Decrement(ref DebugCounters.ClusterHandles);
 }
 protected override void Destroy(IntPtr handle)
 {
     FdbNative.TransactionDestroy(handle);
     Interlocked.Decrement(ref DebugCounters.TransactionHandles);
 }
        /// <summary>Update the Task with the state of a ready Future</summary>
        /// <param name="fromCallback">If true, the method is called from the network thread and must defer the continuations from the Thread Pool</param>
        /// <returns>True if we got a result, or false in case of error (or invalid state)</returns>
        private void HandleCompletion(bool fromCallback)
        {
            if (HasAnyFlags(FdbFuture.Flags.DISPOSED | FdbFuture.Flags.COMPLETED))
            {
                return;
            }

#if DEBUG_FUTURES
            Debug.WriteLine("FutureArray<" + typeof(T).Name + ">.Callback(...) handling completion on thread #" + Thread.CurrentThread.ManagedThreadId.ToString());
#endif

            try
            {
                UnregisterCancellationRegistration();

                List <Exception> errors       = null;
                bool             cancellation = false;
                var selector = m_resultSelector;

                var results = selector != null ? new T[m_handles.Length] : null;

                for (int i = 0; i < m_handles.Length; i++)
                {
                    var handle = m_handles[i];

                    if (handle != null && !handle.IsClosed && !handle.IsInvalid)
                    {
                        FdbError err = FdbNative.FutureGetError(handle);
                        if (Fdb.Failed(err))
                        {                         // it failed...
                            if (err != FdbError.OperationCancelled)
                            {                     // get the exception from the error code
                                var ex = Fdb.MapToException(err);
                                (errors ?? (errors = new List <Exception>())).Add(ex);
                            }
                            else
                            {
                                cancellation = true;
                                break;
                            }
                        }
                        else
                        {                         // it succeeded...
                            // try to get the result...
                            if (selector != null)
                            {
                                //note: result selector will execute from network thread, but this should be our own code that only calls into some fdb_future_get_XXXX(), which should be safe...
                                results[i] = selector(handle);
                            }
                        }
                    }
                }

                if (cancellation)
                {                 // the transaction has been cancelled
                    SetCanceled(fromCallback);
                }
                else if (errors != null)
                {                 // there was at least one error
                    SetFaulted(errors, fromCallback);
                }
                else
                {                  // success
                    SetResult(results, fromCallback);
                }
            }
            catch (Exception e)
            {             // something went wrong
                if (e is ThreadAbortException)
                {
                    SetCanceled(fromCallback);
                    throw;
                }
                SetFaulted(e, fromCallback);
            }
            finally
            {
                TryCleanup();
            }
        }
        internal FdbFutureArray([NotNull] FutureHandle[] handles, [NotNull] Func <FutureHandle, T> selector, CancellationToken ct)
        {
            Contract.NotNullOrEmpty(handles, nameof(handles));
            Contract.NotNull(selector, nameof(selector));

            m_handles        = handles;
            m_resultSelector = selector;

            bool abortAllHandles = false;

            try
            {
                if (ct.IsCancellationRequested)
                {                 // already cancelled, we must abort everything
                    SetFlag(FdbFuture.Flags.COMPLETED);
                    abortAllHandles  = true;
                    m_resultSelector = null;
                    this.TrySetCanceled();
                    return;
                }

                // add this instance to the list of pending futures
                var prm = RegisterCallback(this);

                foreach (var handle in handles)
                {
                    if (FdbNative.FutureIsReady(handle))
                    {                     // this handle is already done
                        continue;
                    }

                    Interlocked.Increment(ref m_pending);

                    // register the callback handler
                    var err = FdbNative.FutureSetCallback(handle, CallbackHandler, prm);
                    if (Fdb.Failed(err))
                    {                     // uhoh
                        Debug.WriteLine("Failed to set callback for Future<" + typeof(T).Name + "> 0x" + handle.Handle.ToString("x") + " !!!");
                        throw Fdb.MapToException(err);
                    }
                }

                // allow the callbacks to handle completion
                TrySetFlag(FdbFuture.Flags.READY);

                if (Volatile.Read(ref m_pending) == 0)
                {                 // all callbacks have already fired (or all handles were already completed)
                    UnregisterCallback(this);
                    HandleCompletion(fromCallback: false);
                    m_resultSelector = null;
                    abortAllHandles  = true;
                    SetFlag(FdbFuture.Flags.COMPLETED);
                }
                else if (ct.CanBeCanceled)
                {                 // register for cancellation (if needed)
                    RegisterForCancellation(ct);
                }
            }
            catch
            {
                // this is bad news, since we are in the constructor, we need to clear everything
                SetFlag(FdbFuture.Flags.DISPOSED);

                UnregisterCancellationRegistration();

                UnregisterCallback(this);

                abortAllHandles = true;

                // this is technically not needed, but just to be safe...
                this.TrySetCanceled();

                throw;
            }
            finally
            {
                if (abortAllHandles)
                {
                    CloseHandles(handles);
                }
            }
            GC.KeepAlive(this);
        }
Esempio n. 5
0
 protected override void Destroy(IntPtr handle)
 {
     FdbNative.DatabaseDestroy(handle);
     Interlocked.Decrement(ref DebugCounters.DatabaseHandles);
 }
Esempio n. 6
0
 public void Cancel()
 {
     FdbNative.TransactionCancel(m_handle);
 }
Esempio n. 7
0
        /// <summary>
        /// Attempts to commit the sets and clears previously applied to the database snapshot represented by this transaction to the actual database.
        /// The commit may or may not succeed – in particular, if a conflicting transaction previously committed, then the commit must fail in order to preserve transactional isolation.
        /// If the commit does succeed, the transaction is durably committed to the database and all subsequently started transactions will observe its effects.
        /// </summary>
        /// <returns>Task that succeeds if the transaction was committed successfully, or fails if the transaction failed to commit.</returns>
        /// <remarks>As with other client/server databases, in some failure scenarios a client may be unable to determine whether a transaction succeeded. In these cases, CommitAsync() will throw CommitUnknownResult error. The OnErrorAsync() function treats this error as retryable, so retry loops that don’t check for CommitUnknownResult could execute the transaction twice. In these cases, you must consider the idempotence of the transaction.</remarks>
        public Task CommitAsync(CancellationToken ct)
        {
            var future = FdbNative.TransactionCommit(m_handle);

            return(FdbFuture.CreateTaskFromHandle <object>(future, (h) => null, ct));
        }
 public DatabaseHandle CreateDatabase(string databaseName)
 {
     FdbNative.CreateDatabase(databaseName, out d_handle);
     return(d_handle);
 }
Esempio n. 9
0
        public void AddConflictRange(Slice beginKeyInclusive, Slice endKeyExclusive, FdbConflictRangeType type)
        {
            FdbError err = FdbNative.TransactionAddConflictRange(m_handle, beginKeyInclusive, endKeyExclusive, type);

            Fdb.DieOnError(err);
        }
Esempio n. 10
0
        public Task <VersionStamp> GetVersionStampAsync(CancellationToken ct)
        {
            var future = FdbNative.TransactionGetVersionStamp(m_handle);

            return(FdbFuture.CreateTaskFromHandle <VersionStamp>(future, GetVersionStampResult, ct));
        }
Esempio n. 11
0
 public void ClearRange(Slice beginKeyInclusive, Slice endKeyExclusive)
 {
     FdbNative.TransactionClearRange(m_handle, beginKeyInclusive, endKeyExclusive);
     // There is an overhead of 28-byte per operation
     Interlocked.Add(ref m_payloadBytes, beginKeyInclusive.Count + endKeyExclusive.Count + 28);
 }
Esempio n. 12
0
 public void Clear(Slice key)
 {
     FdbNative.TransactionClear(m_handle, key);
     // The key is converted to range [key, key.'\0'), and there is an overhead of 28-byte per operation
     Interlocked.Add(ref m_payloadBytes, (key.Count * 2) + 28 + 1);
 }
Esempio n. 13
0
        public Task <Slice> GetAsync(Slice key, bool snapshot, CancellationToken ct)
        {
            var future = FdbNative.TransactionGet(m_handle, key, snapshot);

            return(FdbFuture.CreateTaskFromHandle(future, (h) => GetValueResultBytes(h), ct));
        }
        /// <summary>Update the Task with the state of a ready Future</summary>
        /// <param name="fromCallback">If true, we are called from the network thread</param>
        /// <returns>True if we got a result, or false in case of error (or invalid state)</returns>
        private void HandleCompletion(bool fromCallback)
        {
            // note: if fromCallback is true, we are running on the network thread
            // this means that we have to signal the TCS from the threadpool, if not continuations on the task may run inline.
            // this is very frequent when we are called with await, or ContinueWith(..., TaskContinuationOptions.ExecuteSynchronously)

            if (HasAnyFlags(FdbFuture.Flags.DISPOSED | FdbFuture.Flags.COMPLETED))
            {
                return;
            }

#if DEBUG_FUTURES
            var sw = Stopwatch.StartNew();
#endif
            try
            {
                var handle = m_handle;
                if (handle != null && !handle.IsClosed && !handle.IsInvalid)
                {
                    UnregisterCancellationRegistration();

                    FdbError err = FdbNative.FutureGetError(handle);
                    if (Fdb.Failed(err))
                    {                     // it failed...
#if DEBUG_FUTURES
                        Debug.WriteLine("Future<" + typeof(T).Name + "> has FAILED: " + err);
#endif
                        if (err != FdbError.OperationCancelled)
                        {                         // get the exception from the error code
                            var ex = Fdb.MapToException(err);
                            SetFaulted(ex, fromCallback);
                            return;
                        }
                        //else: will be handle below
                    }
                    else
                    {                     // it succeeded...
                        // try to get the result...
#if DEBUG_FUTURES
                        Debug.WriteLine("Future<" + typeof(T).Name + "> has completed successfully");
#endif
                        var selector = m_resultSelector;
                        if (selector != null)
                        {
                            //note: result selector will execute from network thread, but this should be our own code that only calls into some fdb_future_get_XXXX(), which should be safe...
                            var result = selector(handle);
                            SetResult(result, fromCallback);
                            return;
                        }
                        //else: it will be handled below
                    }
                }

                // most probably the future was cancelled or we are shutting down...
                SetCanceled(fromCallback);
            }
            catch (Exception e)
            {             // something went wrong
                if (e is ThreadAbortException)
                {
                    SetCanceled(fromCallback);
                    throw;
                }
                SetFaulted(e, fromCallback);
            }
            finally
            {
#if DEBUG_FUTURES
                sw.Stop();
                Debug.WriteLine("Future<" + typeof(T).Name + "> callback completed in " + sw.Elapsed.TotalMilliseconds.ToString() + " ms");
#endif
                TryCleanup();
            }
        }
Esempio n. 15
0
        public Task OnErrorAsync(FdbError code, CancellationToken ct)
        {
            var future = FdbNative.TransactionOnError(m_handle, code);

            return(FdbFuture.CreateTaskFromHandle <object>(future, (h) => { ResetInternal(); return null; }, ct));
        }
        internal FdbFutureSingle([NotNull] FutureHandle handle, [NotNull] Func <FutureHandle, T> selector, CancellationToken cancellationToken)
        {
            if (handle == null)
            {
                throw new ArgumentNullException("handle");
            }
            if (selector == null)
            {
                throw new ArgumentNullException("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 (cancellationToken.CanBeCanceled)
                {
                    if (cancellationToken.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(cancellationToken);
                }

#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);
        }
Esempio n. 17
0
 public void Reset()
 {
     FdbNative.TransactionReset(m_handle);
     ResetInternal();
 }
 public void SetReadVersion(long version)
 {
     FdbNative.TransactionSetReadVersion(m_handle, version);
 }
        /// <summary>Update the Task with the state of a ready Future</summary>
        /// <returns>True if we got a result, or false in case of error (or invalid state)</returns>
        private void HandleCompletion()
        {
            if (HasAnyFlags(FdbFuture.Flags.DISPOSED | FdbFuture.Flags.COMPLETED))
            {
                return;
            }

#if DEBUG_FUTURES
            var sw = Stopwatch.StartNew();
#endif
            try
            {
                var handle = m_handle;
                if (handle != null && !handle.IsClosed && !handle.IsInvalid)
                {
                    UnregisterCancellationRegistration();

                    FdbError err = FdbNative.FutureGetError(handle);
                    if (Fdb.Failed(err))
                    {                     // it failed...
#if DEBUG_FUTURES
                        Debug.WriteLine("Future<" + typeof(T).Name + "> has FAILED: " + err);
#endif
                        if (err != FdbError.OperationCancelled)
                        {                         // get the exception from the error code
                            var ex = Fdb.MapToException(err) !;
                            TrySetException(ex);
                            return;
                        }
                        //else: will be handle below
                    }
                    else
                    {                     // it succeeded...
                        // try to get the result...
#if DEBUG_FUTURES
                        Debug.WriteLine("Future<" + typeof(T).Name + "> has completed successfully");
#endif
                        var selector = m_resultSelector;
                        if (selector != null)
                        {
                            //note: result selector will execute from network thread, but this should be our own code that only calls into some fdb_future_get_XXXX(), which should be safe...
                            var result = selector(handle);
                            TrySetResult(result);
                            return;
                        }
                        //else: it will be handled below
                    }
                }

                // most probably the future was cancelled or we are shutting down...
                TrySetCanceled();
            }
            catch (Exception e)
            {             // something went wrong
                if (e is ThreadAbortException)
                {
                    TrySetCanceled();
                    throw;
                }
                TrySetException(e);
            }
            finally
            {
#if DEBUG_FUTURES
                sw.Stop();
                Debug.WriteLine("Future<" + typeof(T).Name + "> callback completed in " + sw.Elapsed.TotalMilliseconds.ToString() + " ms");
#endif
                TryCleanup();
            }
        }