/// <summary>Moves the current directory to <paramref name="newAbsolutePath"/>. /// There is no effect on the physical prefix of the given directory, or on clients that already have the directory open. /// An error is raised if a directory already exists at `new_path`, or if the new path points to a child of the current directory. /// </summary> /// <param name="trans">Transaction to use for the operation</param> /// <param name="newAbsolutePath">Full path (from the root) where this directory will be moved. It must includes all the necessary layer ids (including the parents).</param> public async Task <FdbDirectorySubspace> MoveToAsync(IFdbTransaction trans, FdbPath newAbsolutePath) { Contract.NotNull(trans, nameof(trans)); if (newAbsolutePath.IsEmpty) { throw new ArgumentNullException(nameof(newAbsolutePath)); } EnsureIsValid(); var partition = GetEffectivePartition(); Contract.Assert(partition != null, "Effective partition cannot be null!"); // verify that it is still inside the same partition var location = this.DirectoryLayer.VerifyPath(newAbsolutePath, "newAbsolutePath"); if (!location.StartsWith(partition.Path)) { throw new InvalidOperationException($"Cannot move between partitions ['{location}' is outside '{partition.Path}']"); } var metadata = await this.DirectoryLayer.Resolve(trans); return((await metadata.MoveInternalAsync(trans, this.Descriptor.Path, location, throwOnError: true)) !); }
/// <summary>Create a new location that points to the Directory Subspace at the given path.</summary> /// <param name="path">Absolute path of the target Directory Subspace</param> public FdbDirectorySubspaceLocation(FdbPath path) { if (!path.IsAbsolute) { throw new ArgumentException("Directory Subspace path must absolute.", nameof(path)); } this.Path = path; this.IsPartition = path.LayerId == FdbDirectoryPartition.LayerId; }
/// <summary>Returns the list of all the subdirectories of a sub-directory.</summary> public async Task <List <FdbPath> > ListAsync(IFdbReadOnlyTransaction trans, FdbPath path = default) { Contract.NotNull(trans, nameof(trans)); EnsureIsValid(); var metadata = await this.DirectoryLayer.Resolve(trans); return((await metadata.ListInternalAsync(trans, ToAbsolutePath(path), throwIfMissing: true)) !); }
/// <summary>Convert a path relative to this directory, into a path relative to the root of the current partition</summary> /// <param name="location">Path relative from this directory</param> /// <returns>Path relative to the path of the current partition</returns> protected virtual FdbPath ToAbsolutePath(FdbPath location) { if (location.IsAbsolute) { // we only accept an absolute path if it is technically contained in the current directory if (!location.StartsWith(this.Descriptor.Path)) { throw new InvalidOperationException("Cannot use absolute path that is not contained within the current directory path."); } return(location); } return(this.Descriptor.Path.Add(location)); }
/// <summary>Creates a sub-directory with the given <paramref name="path"/> (creating intermediate subdirectories if necessary). /// An exception is thrown if the given sub-directory already exists. /// </summary> /// <param name="trans">Transaction to use for the operation</param> /// <param name="path">Relative path of the sub-directory to create. It must includes all the necessary layer ids (including the parents).</param> /// <returns></returns> public async Task <FdbDirectorySubspace> CreateAsync(IFdbTransaction trans, FdbPath path) { Contract.NotNull(trans, nameof(trans)); if (path.IsEmpty) { throw new ArgumentNullException(nameof(path)); } EnsureIsValid(); var metadata = await this.DirectoryLayer.Resolve(trans).ConfigureAwait(false); return((await metadata.CreateOrOpenInternalAsync(null, trans, ToAbsolutePath(path), prefix: Slice.Nil, allowCreate: true, allowOpen: false, throwOnError: true).ConfigureAwait(false)) !); }
/// <summary>List and open the sub-directories of the given directory</summary> /// <param name="tr">Transaction used for the operation</param> /// <param name="parent">Parent directory</param> /// <returns>Dictionary of all the sub directories of the <paramref name="parent"/> directory.</returns> public static async Task <Dictionary <string, FdbDirectorySubspace> > BrowseAsync(IFdbReadOnlyTransaction tr, IFdbDirectory parent) { Contract.NotNull(tr, nameof(tr)); Contract.NotNull(parent, nameof(parent)); // read the names of all the subdirectories var children = await parent.ListAsync(tr).ConfigureAwait(false); // open all the subdirectories var folders = await children .ToAsyncEnumerable() .SelectAsync((child, _) => parent.OpenAsync(tr, FdbPath.Relative(child.Name))) .ToListAsync(); // map the result return(folders.ToDictionary(ds => ds.Name)); }
/// <summary>Checks if a sub-directory exists</summary> /// <returns>Returns true if the directory exists, otherwise false.</returns> public async Task <bool> ExistsAsync(IFdbReadOnlyTransaction trans, FdbPath path) { Contract.NotNull(trans, nameof(trans)); EnsureIsValid(); // If path is empty, we are checking ourselves! var location = this.DirectoryLayer.VerifyPath(path, nameof(path)); if (location.Count == 0) { return(await ExistsAsync(trans)); } var metadata = await this.DirectoryLayer.Resolve(trans); return(await metadata.ExistsInternalAsync(trans, ToAbsolutePath(location))); }
/// <summary>Attempts to remove a sub-directory, its contents, and all subdirectories. /// Warning: Clients that have already opened the directory might still insert data into its contents after it is removed. /// </summary> /// <param name="trans">Transaction to use for the operation</param> /// <param name="path">Path of the sub-directory to remove (relative to this directory)</param> public async Task <bool> TryRemoveAsync(IFdbTransaction trans, FdbPath path) { Contract.NotNull(trans, nameof(trans)); EnsureIsValid(); // If path is empty, we are removing ourselves! var location = this.DirectoryLayer.VerifyPath(path, nameof(path)); if (location.Count == 0) { return(await TryRemoveAsync(trans)); } var metadata = await this.DirectoryLayer.Resolve(trans); return(await metadata.RemoveInternalAsync(trans, ToAbsolutePath(location), throwIfMissing : false)); }
/// <summary>Removes a sub-directory, its contents, and all subdirectories. /// Warning: Clients that have already opened the directory might still insert data into its contents after it is removed. /// </summary> /// <param name="trans">Transaction to use for the operation</param> /// <param name="path">Path of the sub-directory to remove (relative to this directory)</param> public async Task RemoveAsync(IFdbTransaction trans, FdbPath path) { Contract.NotNull(trans, nameof(trans)); EnsureIsValid(); // If path is empty, we are removing ourselves! var location = this.DirectoryLayer.VerifyPath(path, nameof(path)); if (location.Count == 0) { await RemoveAsync(trans).ConfigureAwait(false); } else { var metadata = await this.DirectoryLayer.Resolve(trans).ConfigureAwait(false); await metadata.RemoveInternalAsync(trans, ToAbsolutePath(location), throwIfMissing : true).ConfigureAwait(false); } }
/// <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()}"); } } }
/// <inheritdoc /> public Task <bool> TryRemoveAsync(IFdbTransaction trans, FdbPath path = default) { return(trans.Context.Database.DirectoryLayer.TryRemoveAsync(trans, this.Path.Add(path))); }
/// <summary>Attempts to move the specified sub-directory to <paramref name="newPath"/>. /// There is no effect on the physical prefix of the given directory, or on clients that already have the directory open. /// An error is raised if a directory already exists at `new_path`. /// </summary> /// <param name="trans">Transaction to use for the operation</param> /// <param name="oldPath">Relative path under this directory of the sub-directory to be moved</param> /// <param name="newPath">Relative path under this directory where the sub-directory will be moved to</param> /// <returns>Returns the directory at its new location if successful. If the directory cannot be moved, then null is returned.</returns> Task <FdbDirectorySubspace?> IFdbDirectory.TryMoveAsync(IFdbTransaction trans, FdbPath oldPath, FdbPath newPath) { if (oldPath.IsEmpty) { throw new ArgumentNullException(nameof(oldPath)); } if (newPath.IsEmpty) { throw new ArgumentNullException(nameof(newPath)); } EnsureIsValid(); return(this.DirectoryLayer.TryMoveAsync(trans, ToAbsolutePath(oldPath), ToAbsolutePath(newPath))); }
/// <summary>Attempts to move the current directory to <paramref name="newPath"/>. /// There is no effect on the physical prefix of the given directory, or on clients that already have the directory open. /// </summary> /// <param name="trans">Transaction to use for the operation</param> /// <param name="newPath">Full path (from the root) where this directory will be moved. It must includes all the necessary layer ids (including the parents).</param> public async Task <FdbDirectorySubspace?> TryMoveToAsync(IFdbTransaction trans, FdbPath newPath) { Contract.NotNull(trans, nameof(trans)); if (newPath.IsEmpty) { throw new ArgumentNullException(nameof(newPath)); } EnsureIsValid(); var descriptor = this.Descriptor; var location = this.DirectoryLayer.VerifyPath(newPath, "newPath"); if (!location.StartsWith(descriptor.Partition.Path)) { throw ThrowHelper.InvalidOperationException("Cannot move between partitions."); } if (location.LayerId != this.Path.LayerId) { throw ThrowHelper.InvalidOperationException("Cannot change the layer id of a directory subspace while moving it to a new location."); } var metadata = await descriptor.DirectoryLayer.Resolve(trans).ConfigureAwait(false); return(await metadata.MoveInternalAsync(trans, descriptor.Path, location, throwOnError : false).ConfigureAwait(false)); }
/// <summary>Moves the specified sub-directory to <paramref name="newPath"/>. /// There is no effect on the physical prefix of the given directory, or on clients that already have the directory open. /// An error is raised if a directory already exists at `new_path`. /// </summary> /// <param name="trans">Transaction to use for the operation</param> /// <param name="oldPath">Relative path under this directory of the sub-directory to be moved</param> /// <param name="newPath">Relative path under this directory where the sub-directory will be moved to</param> /// <returns>Returns the directory at its new location if successful.</returns> async Task <FdbDirectorySubspace> IFdbDirectory.MoveAsync(IFdbTransaction trans, FdbPath oldPath, FdbPath newPath) { if (oldPath.IsEmpty) { throw new ArgumentNullException(nameof(oldPath)); } if (newPath.IsEmpty) { throw new ArgumentNullException(nameof(newPath)); } EnsureIsValid(); var metadata = await this.DirectoryLayer.Resolve(trans); return((await metadata.MoveInternalAsync(trans, ToAbsolutePath(oldPath), ToAbsolutePath(newPath), throwOnError: true)) !); }
/// <inheritdoc /> public Task <FdbDirectorySubspace?> TryCreateAsync(IFdbTransaction trans, FdbPath subPath = default) { return(trans.Context.Database.DirectoryLayer.TryCreateAsync(trans, this.Path.Add(subPath))); }
/// <inheritdoc /> public Task <bool> ExistsAsync(IFdbReadOnlyTransaction trans, FdbPath path = default) { return(trans.Context.Database.DirectoryLayer.ExistsAsync(trans, this.Path.Add(path))); }
/// <inheritdoc /> public ValueTask <FdbDirectorySubspace?> TryOpenCachedAsync(IFdbReadOnlyTransaction trans, FdbPath path = default) { return(trans.Context.Database.DirectoryLayer.TryOpenCachedAsync(trans, this.Path.Add(path))); }
/// <inheritdoc /> public Task <FdbDirectorySubspace?> TryMoveToAsync(IFdbTransaction trans, FdbPath newAbsolutePath) { return(trans.Context.Database.DirectoryLayer.TryMoveAsync(trans, this.Path, newAbsolutePath)); }
/// <inheritdoc /> Task <FdbDirectorySubspace?> IFdbDirectory.TryMoveAsync(IFdbTransaction trans, FdbPath oldPath, FdbPath newPath) => throw new NotSupportedException();
/// <inheritdoc /> Task <FdbDirectorySubspace> IFdbDirectory.RegisterAsync(IFdbTransaction trans, FdbPath subPath, Slice prefix) => throw new NotSupportedException();
/// <inheritdoc /> public Task <List <FdbPath>?> TryListAsync(IFdbReadOnlyTransaction trans, FdbPath path = default) { return(trans.Context.Database.DirectoryLayer.TryListAsync(trans, this.Path.Add(path))); }
public async ValueTask <FdbDirectorySubspace?> TryOpenCachedAsync(IFdbReadOnlyTransaction trans, FdbPath path) { Contract.NotNull(trans, nameof(trans)); if (path.IsEmpty) { throw new InvalidOperationException("Cannot open empty path"); } EnsureIsValid(); var metadata = await this.DirectoryLayer.Resolve(trans); return(await metadata.OpenCachedInternalAsync(trans, ToAbsolutePath(path), throwOnError : false)); }
/// <summary>Append a relative path to the current path</summary> public FdbDirectorySubspaceLocation this[FdbPath relativePath] => !relativePath.IsEmpty ? new FdbDirectorySubspaceLocation(this.Path.Add(relativePath)) : this;