/// <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}"); } }
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)); }
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)); }
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(); } } }