Пример #1
0
            public static async Task <IFdbDatabase> OpenNamedPartitionAsync(string clusterFile, string dbName, [NotNull] IEnumerable <string> path, bool readOnly, CancellationToken ct)
            {
                if (path == null)
                {
                    throw new ArgumentNullException(nameof(path));
                }
                var partitionPath = path.ToList();

                if (partitionPath.Count == 0)
                {
                    throw new ArgumentException("The path to the named partition cannot be empty", nameof(path));
                }

                // looks at the global partition table for the specified named partition

                // By convention, all named databases will be under the "/Databases" folder
                FdbDatabase db        = null;
                var         rootSpace = KeySubspace.Empty;

                try
                {
                    db = await Fdb.OpenInternalAsync(clusterFile, dbName, rootSpace, readOnly : false, ct : ct).ConfigureAwait(false);

                    var rootLayer = FdbDirectoryLayer.Create(rootSpace);
                    if (Logging.On)
                    {
                        Logging.Verbose(typeof(Fdb.Directory), "OpenNamedPartitionAsync", $"Opened root layer of database {db.Name} using cluster file '{db.Cluster.Path}'");
                    }

                    // look up in the root layer for the named partition
                    var descriptor = await rootLayer.CreateOrOpenAsync(db, partitionPath, layer : FdbDirectoryPartition.LayerId, ct : ct).ConfigureAwait(false);

                    if (Logging.On)
                    {
                        Logging.Verbose(typeof(Fdb.Directory), "OpenNamedPartitionAsync", $"Found named partition '{descriptor.FullName}' at prefix {descriptor}");
                    }

                    // we have to chroot the database to the new prefix, and create a new DirectoryLayer with a new '/'
                    rootSpace = descriptor.Copy();                     //note: create a copy of the key
                    //TODO: find a nicer way to do that!
                    db.ChangeRoot(rootSpace, FdbDirectoryLayer.Create(rootSpace, partitionPath), readOnly);

                    if (Logging.On)
                    {
                        Logging.Info(typeof(Fdb.Directory), "OpenNamedPartitionAsync", $"Opened partition {descriptor.FullName} at {db.GlobalSpace}, using directory layer at {db.Directory.DirectoryLayer.NodeSubspace}");
                    }

                    return(db);
                }
                catch (Exception e)
                {
                    db?.Dispose();
                    if (Logging.On)
                    {
                        Logging.Exception(typeof(Fdb.Directory), "OpenNamedPartitionAsync", e);
                    }
                    throw;
                }
            }
Пример #2
0
        /// <summary>Set an option on this cluster that does not take any parameter</summary>
        /// <param name="option">Option to set</param>
        public void SetOption(FdbClusterOption option)
        {
            ThrowIfDisposed();

            Fdb.EnsureNotOnNetworkThread();

            if (Logging.On && Logging.IsVerbose)
            {
                Logging.Verbose(this, "SetOption", $"Setting cluster option {option.ToString()}");
            }

            m_handler.SetOption(option, Slice.Nil);
        }
Пример #3
0
        /// <summary>Set an option on this cluster that takes an integer value</summary>
        /// <param name="option">Option to set</param>
        /// <param name="value">Value of the parameter</param>
        public void SetOption(FdbClusterOption option, long value)
        {
            ThrowIfDisposed();

            Fdb.EnsureNotOnNetworkThread();

            if (Logging.On && Logging.IsVerbose)
            {
                Logging.Verbose(this, "SetOption", $"Setting cluster option {option.ToString()} to {value}");
            }

            var data = Slice.FromFixed64(value);

            m_handler.SetOption(option, data);
        }
Пример #4
0
        /// <summary>Set an option on this cluster that takes a string value</summary>
        /// <param name="option">Option to set</param>
        /// <param name="value">Value of the parameter (can be null)</param>
        public void SetOption(FdbClusterOption option, string value)
        {
            ThrowIfDisposed();

            Fdb.EnsureNotOnNetworkThread();

            if (Logging.On && Logging.IsVerbose)
            {
                Logging.Verbose(this, "SetOption", $"Setting cluster option {option.ToString()} to '{value ?? "<null>"}'");
            }

            var data = FdbNative.ToNativeString(value, nullTerminated: true);

            m_handler.SetOption(option, data);
        }
            public static async Task <IFdbDatabase> OpenNamedPartitionAsync(string clusterFile, string dbName, [NotNull] IEnumerable <string> path, bool readOnly, CancellationToken ct)
            {
                Contract.NotNull(path, nameof(path));
                var partitionPath = (path as string[]) ?? path.ToArray();

                if (partitionPath.Length == 0)
                {
                    throw new ArgumentException("The path to the named partition cannot be empty", nameof(path));
                }

                var options = new FdbConnectionOptions
                {
                    ClusterFile   = clusterFile,
                    DbName        = dbName,
                    PartitionPath = partitionPath,
                };
                var db = await Fdb.OpenInternalAsync(options, ct).ConfigureAwait(false);

                return(db);
            }
        /// <summary>Throws if the transaction is not in a valid state (for reading/writing) and that we can proceed with a read or write operation</summary>
        /// <param name="allowFromNetworkThread">If true, this operation is allowed to run from a callback on the network thread and should NEVER block.</param>
        /// <param name="allowFailedState">If true, this operation can run even if the transaction is in a failed state.</param>
        /// <exception cref="System.ObjectDisposedException">If Dispose as already been called on the transaction</exception>
        /// <exception cref="System.InvalidOperationException">If CommitAsync() or Rollback() have already been called on the transaction, or if the database has been closed</exception>
        internal void EnsureStilValid(bool allowFromNetworkThread = false, bool allowFailedState = false)
        {
            // We must not be disposed
            if (allowFailedState ? this.State == STATE_DISPOSED : this.State != STATE_READY)
            {
                ThrowOnInvalidState(this);
            }

            // The cancellation token should not be signaled
            m_cancellation.ThrowIfCancellationRequested();

            // We cannot be called from the network thread (or else we will deadlock)
            if (!allowFromNetworkThread)
            {
                Fdb.EnsureNotOnNetworkThread();
            }

            // Ensure that the DB is still opened and that this transaction is still registered with it
            this.Database.EnsureTransactionIsValid(this);

            // we are ready to go !
        }
        /// <summary>Checks that this type of mutation is supported by the currently selected API level</summary>
        /// <param name="mutation">Mutation type</param>
        /// <param name="selectedApiVersion">Select API level (200, 300, ...)</param>
        /// <exception cref="FdbException">An error with code <see cref="FdbError.InvalidMutationType"/> if the type of mutation is not supported by this API level.</exception>
        private static void EnsureMutationTypeIsSupported(FdbMutationType mutation, int selectedApiVersion)
        {
            if (selectedApiVersion < 200)
            {             // mutations were not available at this time
                if (Fdb.GetMaxApiVersion() >= 200)
                {         // but the installed client could support it
                    throw new FdbException(FdbError.InvalidMutationType, "Atomic mutations are only supported starting from API level 200. You need to select API level 200 or more at the start of your process.");
                }
                else
                {                 // not supported by the local client
                    throw new FdbException(FdbError.InvalidMutationType, "Atomic mutations are only supported starting from client version 2.x. You need to update the version of the client, and select API level 200 or more at the start of your process.");
                }
            }

            if (mutation == FdbMutationType.Add || mutation == FdbMutationType.BitAnd || mutation == FdbMutationType.BitOr || mutation == FdbMutationType.BitXor)
            {             // these mutations are available since v200
                return;
            }

            if (mutation == FdbMutationType.Max || mutation == FdbMutationType.Min)
            {             // these mutations are available since v300
                if (selectedApiVersion < 300)
                {
                    if (Fdb.GetMaxApiVersion() >= 300)
                    {
                        throw new FdbException(FdbError.InvalidMutationType, "Atomic mutations Max and Min are only supported starting from API level 300. You need to select API level 300 or more at the start of your process.");
                    }
                    else
                    {
                        throw new FdbException(FdbError.InvalidMutationType, "Atomic mutations Max and Min are only supported starting from client version 3.x. You need to update the version of the client, and select API level 300 or more at the start of your process..");
                    }
                }
                // ok!
                return;
            }

            // this could be a new mutation type, or an invalid value.
            throw new FdbException(FdbError.InvalidMutationType, "An invalid mutation type was issued. If you are attempting to call a new mutation type, you will need to update the version of this assembly, and select the latest API level.");
        }
Пример #8
0
        /// <summary>Stops the thread running the FDB event loop</summary>
        private static void StopEventLoop()
        {
            if (s_eventLoopStarted)
            {
                // We cannot be called from the network thread itself, or else we will dead lock !
                Fdb.EnsureNotOnNetworkThread();

                if (Logging.On)
                {
                    Logging.Verbose(typeof(Fdb), "StopEventLoop", "Stopping network thread...");
                }

                s_eventLoopStopRequested = true;

                var err = FdbNative.StopNetwork();
                if (err != FdbError.Success)
                {
                    if (Logging.On)
                    {
                        Logging.Warning(typeof(Fdb), "StopEventLoop", $"Failed to stop event loop: {err.ToString()}");
                    }
                }
                s_eventLoopStarted = false;

                var thread = s_eventLoop;
                if (thread != null && thread.IsAlive)
                {
                    // BUGBUG: specs says that we need to wait for the network thread to stop gracefuly, or else data integrity may not be guaranteed...
                    // We should wait for a bit, and only attempt to Abort() the thread after a timeout (30sec ? more ?)

                    // keep track of how much time it took to stop...
                    var duration = Stopwatch.StartNew();

                    try
                    {
                        //TODO: replace with a ManualResetEvent that would get signaled at the end of the event loop ?
                        while (thread.IsAlive && duration.Elapsed.TotalSeconds < 5)
                        {
                            // wait a bit...
                            Thread.Sleep(250);
                        }

                        if (thread.IsAlive)
                        {
                            if (Logging.On)
                            {
                                Logging.Warning(typeof(Fdb), "StopEventLoop", $"The fdb network thread has not stopped after {duration.Elapsed.TotalSeconds:N0} seconds. Forcing shutdown...");
                            }

                            // Force a shutdown
                            thread.Abort();

                            bool stopped = thread.Join(TimeSpan.FromSeconds(30));
                            //REVIEW: is this even usefull? If the thread is stuck in a native P/Invoke call, it won't get notified until it returns to managed code ...
                            // => in that case, we have a zombie thread on our hands...

                            if (!stopped)
                            {
                                if (Logging.On)
                                {
                                    Logging.Warning(typeof(Fdb), "StopEventLoop", $"The fdb network thread failed to stop after more than {duration.Elapsed.TotalSeconds:N0} seconds. Transaction integrity may not be guaranteed.");
                                }
                            }
                        }
                    }
                    catch (ThreadAbortException)
                    {
                        // Should not happen, unless we are called from a thread that is itself being stopped ?
                    }
                    finally
                    {
                        s_eventLoop = null;
                        duration.Stop();
                        if (duration.Elapsed.TotalSeconds >= 20)
                        {
                            if (Logging.On)
                            {
                                Logging.Warning(typeof(Fdb), "StopEventLoop", $"The fdb network thread took a long time to stop ({duration.Elapsed.TotalSeconds:N0} seconds).");
                            }
                        }
                    }
                }
            }
        }
Пример #9
0
 public FdbException(FdbError errorCode)
     : this(errorCode, Fdb.GetErrorMessage(errorCode), null)
 {
 }
Пример #10
0
 public static IFdbDatabaseScopeProvider AsDatabaseProvider([NotNull] this IFdbDatabase db)
 {
     return(Fdb.CreateRootScope(db));
 }