/// <summary>Opens a named partition, and change the root subspace of the database to the corresponding prefix</summary>
            internal static async Task SwitchToNamedPartitionAsync([NotNull] FdbDatabase db, [NotNull, ItemNotNull] string[] path, bool readOnly, CancellationToken ct)
            {
                Contract.Requires(db != null && path != null);
                ct.ThrowIfCancellationRequested();

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

                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 db.Directory.CreateOrOpenAsync(path, 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 '/'
                var rootSpace = descriptor.Copy();                 //note: create a copy of the key

                //TODO: find a nicer way to do that!
                db.ChangeRoot(rootSpace, FdbDirectoryLayer.Create(rootSpace, path), 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}");
                }
            }
示例#2
0
        internal async Task <FdbDatabase> OpenDatabaseInternalAsync(string databaseName, IKeySubspace subspace, bool readOnly, bool ownsCluster, CancellationToken ct)
        {
            ThrowIfDisposed();
            Contract.NotNullOrEmpty(databaseName, nameof(databaseName));
            Contract.NotNull(subspace, nameof(subspace));

            if (Logging.On)
            {
                Logging.Info(typeof(FdbCluster), "OpenDatabaseAsync", $"Connecting to database '{databaseName}' ...");
            }

            if (ct.IsCancellationRequested)
            {
                ct.ThrowIfCancellationRequested();
            }

            var handler = await m_handler.OpenDatabaseAsync(databaseName, ct).ConfigureAwait(false);

            if (Logging.On && Logging.IsVerbose)
            {
                Logging.Verbose(typeof(FdbCluster), "OpenDatabaseAsync", $"Connected to database '{databaseName}'");
            }

            return(FdbDatabase.Create(this, handler, databaseName, subspace, null, readOnly, ownsCluster));
        }
示例#3
0
        internal async Task <FdbDatabase> OpenDatabaseInternalAsync(string databaseName, IFdbSubspace subspace, bool readOnly, bool ownsCluster, CancellationToken cancellationToken)
        {
            ThrowIfDisposed();
            if (string.IsNullOrEmpty(databaseName))
            {
                throw new ArgumentNullException("databaseName");
            }
            if (subspace == null)
            {
                throw new ArgumentNullException("subspace");
            }

            if (Logging.On)
            {
                Logging.Info(typeof(FdbCluster), "OpenDatabaseAsync", String.Format("Connecting to database '{0}' ...", databaseName));
            }

            if (cancellationToken.IsCancellationRequested)
            {
                cancellationToken.ThrowIfCancellationRequested();
            }

            var handler = await m_handler.OpenDatabaseAsync(databaseName, cancellationToken).ConfigureAwait(false);

            if (Logging.On && Logging.IsVerbose)
            {
                Logging.Verbose(typeof(FdbCluster), "OpenDatabaseAsync", String.Format("Connected to database '{0}'", databaseName));
            }

            return(FdbDatabase.Create(this, handler, databaseName, subspace, null, readOnly, ownsCluster));
        }
示例#4
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;
                }
            }
        /// <summary>Checks that a key is inside the global namespace of this database, and contained in the optional legal key space specified by the user</summary>
        /// <param name="db">Database instance</param>
        /// <param name="key">Key to verify</param>
        /// <param name="endExclusive">If true, the key is allowed to be one past the maximum key allowed by the global namespace</param>
        /// <exception cref="FdbException">If the key is outside of the allowed keyspace, throws an FdbException with code FdbError.KeyOutsideLegalRange</exception>
        internal static void EnsureKeyIsValid([NotNull] this IFdbDatabase db, ref Slice key, bool endExclusive = false)
        {
            Exception ex;

            if (!FdbDatabase.ValidateKey(db, ref key, endExclusive, false, out ex))
            {
                throw ex;
            }
        }
 /// <summary>Checks that one or more keys are inside the global namespace of this database, and contained in the optional legal key space specified by the user</summary>
 /// <param name="db">Database instance</param>
 /// <param name="keys">Array of keys to verify</param>
 /// <param name="endExclusive">If true, the keys are allowed to be one past the maximum key allowed by the global namespace</param>
 /// <exception cref="FdbException">If at least on key is outside of the allowed keyspace, throws an FdbException with code FdbError.KeyOutsideLegalRange</exception>
 internal static void EnsureKeysAreValid([NotNull] this IFdbDatabase db, Slice[] keys, bool endExclusive = false)
 {
     Contract.NotNull(keys, nameof(keys));
     for (int i = 0; i < keys.Length; i++)
     {
         Exception ex;
         if (!FdbDatabase.ValidateKey(db, ref keys[i], endExclusive, false, out ex))
         {
             throw ex;
         }
     }
 }
        private CancellationToken m_cancellation;         //PERF: readonly struct

        #endregion

        #region Constructors...

        internal FdbTransaction(FdbDatabase db, FdbOperationContext context, int id, IFdbTransactionHandler handler, FdbTransactionMode mode)
        {
            Contract.Requires(db != null && context != null && handler != null);
            Contract.Requires(context.Database != null);

            m_context  = context;
            m_database = db;
            m_id       = id;
            //REVIEW: the operation context may already have created its own CTS, maybe we can merge them ?
            m_cts          = CancellationTokenSource.CreateLinkedTokenSource(context.Cancellation);
            m_cancellation = m_cts.Token;

            m_readOnly = (mode & FdbTransactionMode.ReadOnly) != 0;
            m_handler  = handler;
        }
 /// <summary>Checks that one or more keys are inside the global namespace of this database, and contained in the optional legal key space specified by the user</summary>
 /// <param name="db">Database instance</param>
 /// <param name="keys">Array of keys to verify</param>
 /// <param name="endExclusive">If true, the keys are allowed to be one past the maximum key allowed by the global namespace</param>
 /// <exception cref="FdbException">If at least on key is outside of the allowed keyspace, throws an FdbException with code FdbError.KeyOutsideLegalRange</exception>
 internal static void EnsureKeysAreValid(this IFdbDatabase db, Slice[] keys, bool endExclusive = false)
 {
     if (keys == null)
     {
         throw new ArgumentNullException("keys");
     }
     for (int i = 0; i < keys.Length; i++)
     {
         Exception ex;
         if (!FdbDatabase.ValidateKey(db, ref keys[i], endExclusive, false, out ex))
         {
             throw ex;
         }
     }
 }
        internal static async Task <FdbDatabase> OpenInternalAsync(string clusterFile, string dbName, IFdbSubspace globalSpace, bool readOnly, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            dbName      = dbName ?? "DB";
            globalSpace = globalSpace ?? FdbSubspace.Empty;

            if (Logging.On)
            {
                Logging.Info(typeof(Fdb), "OpenAsync", String.Format("Connecting to database '{0}' using cluster file '{1}' and subspace '{2}' ...", dbName, clusterFile, globalSpace));
            }

            FdbCluster  cluster = null;
            FdbDatabase db      = null;
            bool        success = false;

            try
            {
                cluster = await CreateClusterInternalAsync(clusterFile, cancellationToken).ConfigureAwait(false);

                //note: since the cluster is not provided by the caller, link it with the database's Dispose()
                db = await cluster.OpenDatabaseInternalAsync(dbName, globalSpace, readOnly : readOnly, ownsCluster : true, cancellationToken : cancellationToken).ConfigureAwait(false);

                success = true;
                return(db);
            }
            finally
            {
                if (!success)
                {
                    // cleanup the cluter if something went wrong
                    if (db != null)
                    {
                        db.Dispose();
                    }
                    if (cluster != null)
                    {
                        cluster.Dispose();
                    }
                }
            }
        }
            /// <summary>Opens a named partition, and change the root subspace of the database to the corresponding prefix</summary>
            internal static async Task SwitchToNamedPartitionAsync(FdbDatabase db, FdbPath root, CancellationToken ct)
            {
                Contract.Requires(db != null);
                ct.ThrowIfCancellationRequested();

                if (Logging.On)
                {
                    Logging.Verbose(typeof(Fdb.Directory), "OpenNamedPartitionAsync", $"Opened root layer using cluster file '{db.ClusterFile}'");
                }

                if (root.Count != 0)
                {
                    // create the root partition if does not already exist
                    var descriptor = await db.ReadWriteAsync(tr => db.DirectoryLayer.CreateOrOpenAsync(tr, root), ct).ConfigureAwait(false);

                    if (Logging.On)
                    {
                        Logging.Info(typeof(Fdb.Directory), "OpenNamedPartitionAsync", $"Opened partition {descriptor.Path} at {descriptor.GetPrefixUnsafe()}");
                    }
                }
            }
        public static bool IsKeyValid([NotNull] this IFdbDatabase db, Slice key)
        {
            Exception _;

            return(FdbDatabase.ValidateKey(db, ref key, false, true, out _));
        }
 internal static Exception FailedToRegisterTransactionOnDatabase(IFdbTransaction transaction, FdbDatabase db)
 {
     Contract.Requires(transaction != null && db != null);
     return(new InvalidOperationException($"Failed to register transaction #{transaction.Id}"));
 }
 internal static Exception FailedToRegisterTransactionOnDatabase(IFdbTransaction transaction, FdbDatabase db)
 {
     Contract.Requires(transaction != null && db != null);
     return(new InvalidOperationException(String.Format("Failed to register transaction #{0} with this instance of database {1}", transaction.Id, db.Name)));
 }
        internal static async Task <IFdbDatabase> OpenInternalAsync(FdbConnectionOptions options, CancellationToken ct)
        {
            Contract.Requires(options != null);
            ct.ThrowIfCancellationRequested();

            string       clusterFile = options.ClusterFile;
            string       dbName      = options.DbName ?? FdbConnectionOptions.DefaultDbName;  // new FdbConnectionOptions { GlobalSpace =
            bool         readOnly    = options.ReadOnly;
            IKeySubspace globalSpace = options.GlobalSpace ?? KeySubspace.Empty;

            string[] partitionPath = options.PartitionPath?.ToArray();
            bool     hasPartition  = partitionPath != null && partitionPath.Length > 0;

            if (Logging.On)
            {
                Logging.Info(typeof(Fdb), nameof(OpenInternalAsync), $"Connecting to database '{dbName}' using cluster file '{clusterFile}' and subspace '{globalSpace}' ...");
            }

            FdbCluster  cluster = null;
            FdbDatabase db      = null;
            bool        success = false;

            try
            {
                cluster = await CreateClusterInternalAsync(clusterFile, ct).ConfigureAwait(false);

                //note: since the cluster is not provided by the caller, link it with the database's Dispose()
                db = await cluster.OpenDatabaseInternalAsync(dbName, globalSpace, readOnly : !hasPartition && readOnly, ownsCluster : true, ct : ct).ConfigureAwait(false);

                // set the default options
                if (options.DefaultTimeout != TimeSpan.Zero)
                {
                    db.DefaultTimeout = checked ((int)Math.Ceiling(options.DefaultTimeout.TotalMilliseconds));
                }
                if (options.DefaultRetryLimit != 0)
                {
                    db.DefaultRetryLimit = options.DefaultRetryLimit;
                }
                if (options.DefaultMaxRetryDelay != 0)
                {
                    db.DefaultMaxRetryDelay = options.DefaultMaxRetryDelay;
                }

                if (hasPartition)
                {                 // open the partition, and switch the root of the db
                    await Fdb.Directory.SwitchToNamedPartitionAsync(db, partitionPath, readOnly, ct);
                }

                success = true;
                return(db);
            }
            finally
            {
                if (!success)
                {
                    // cleanup the cluter if something went wrong
                    db?.Dispose();
                    cluster?.Dispose();
                }
            }
        }