public static void Deconstruct <T1, T2, T3>(this IVarTuple value, out T1 item1, out T2 item2, out T3 item3) { value.OfSize(3); item1 = value.Get <T1>(0); item2 = value.Get <T2>(1); item3 = value.Get <T3>(2); }
public static async Task Shards(string[] path, IVarTuple extras, IFdbDatabase db, TextWriter log, CancellationToken ct) { var ranges = await Fdb.System.GetChunksAsync(db, FdbKey.MinValue, FdbKey.MaxValue, ct); Console.WriteLine($"Found {ranges.Count} shards in the whole cluster"); // look if there is something under there if ((await TryOpenCurrentDirectoryAsync(path, db, ct)) is FdbDirectorySubspace folder) { var r = KeyRange.StartsWith(folder.Copy().GetPrefix()); Console.WriteLine($"Searching for shards that intersect with /{String.Join("/", path)} ..."); ranges = await Fdb.System.GetChunksAsync(db, r, ct); Console.WriteLine($"> Found {ranges.Count} ranges intersecting {r}:"); var last = Slice.Empty; foreach (var range in ranges) { Console.Write($"> {FdbKey.Dump(range.Begin)} ..."); long count = await Fdb.System.EstimateCountAsync(db, range, ct); Console.WriteLine($" {count:N0}"); last = range.End; //TODO: we can probably get more details on this shard looking in the system keyspace (where it is, how many replicas, ...) } Console.WriteLine($"> ... {FdbKey.Dump(last)}"); } //Console.WriteLine("Found " + ranges.Count + " shards in the cluster"); //TODO: shards that intersect the current directory }
/// <summary>Counts the number of keys inside a directory</summary> public static async Task Count(string[] path, IVarTuple extras, IFdbDatabase db, TextWriter log, CancellationToken ct) { // look if there is something under there var folder = (await TryOpenCurrentDirectoryAsync(path, db, ct)) as FdbDirectorySubspace; if (folder == null) { Program.Error(log, $"# Directory {String.Join("/", path)} does not exist"); return; } var copy = folder.Copy(); log.WriteLine($"# Counting keys under {FdbKey.Dump(copy.GetPrefix())} ..."); var progress = new Progress <(long Count, Slice Current)>((state) => { log.Write($"\r# Found {state.Count:N0} keys..."); }); long count = await Fdb.System.EstimateCountAsync(db, copy.ToRange(), progress, ct); log.Write("\r"); Program.Success(log, $"Found {count:N0} keys in {folder.FullName}"); }
public static void Deconstruct <T1, T2, T3>(this IVarTuple value, [MaybeNull] out T1 item1, [MaybeNull] out T2 item2, [MaybeNull] out T3 item3) { value.OfSize(3); item1 = value.Get <T1>(0) !; item2 = value.Get <T2>(1) !; item3 = value.Get <T3>(2) !; }
/// <summary>Shows the first few keys of a directory</summary> public static async Task Show(string[] path, IVarTuple extras, bool reverse, IFdbDatabase db, TextWriter log, CancellationToken ct) { int count = 20; if (extras.Count > 0) { int x = extras.Get <int>(0); if (x > 0) { count = x; } } if (path == null || path.Length == 0) { Program.Error(log, "Cannot directory list the content of Root Partition."); return; } // look if there is something under there var folder = await db.Directory.TryOpenAsync(db, path, ct : ct); if (folder != null) { if (folder.Layer == FdbDirectoryPartition.LayerId) { Program.Error(log, "Cannot list the content of a Directory Partition!"); return; } Program.Comment(log, $"# Content of {FdbKey.Dump(folder.GetPrefix())} [{folder.GetPrefix().ToHexaString(' ')}]"); var keys = await db.QueryAsync((tr) => { var query = tr.GetRange(folder.Keys.ToRange()); return(reverse ? query.Reverse().Take(count) : query.Take(count + 1)); }, ct : ct); if (keys.Count > 0) { if (reverse) { keys.Reverse(); } foreach (var key in keys.Take(count)) { log.WriteLine($"...{FdbKey.Dump(folder.ExtractKey(key.Key))} = {key.Value:V}"); } if (!reverse && keys.Count == count + 1) { log.WriteLine("... more"); } } else { log.WriteLine("Folder is empty"); } } }
/// <summary>Default (non-optimized) implementation for ITuple.StartsWith()</summary> /// <param name="a">Larger tuple</param> /// <param name="b">Smaller tuple</param> /// <returns>True if <paramref name="a"/> starts with (or is equal to) <paramref name="b"/></returns> public static bool StartsWith([NotNull] IVarTuple a, [NotNull] IVarTuple b) { Contract.Requires(a != null && b != null); if (object.ReferenceEquals(a, b)) { return(true); } int an = a.Count; int bn = b.Count; if (bn > an) { return(false); } if (bn == 0) { return(true); // note: 'an' can only be 0 because of previous test } for (int i = 0; i < bn; i++) { if (!object.Equals(a[i], b[i])) { return(false); } } return(true); }
/// <summary>Remove a directory and all its data</summary> public static async Task RemoveDirectory(string[] path, IVarTuple extras, IFdbDatabase db, TextWriter log, CancellationToken ct) { if (log == null) { log = Console.Out; } string layer = extras.Count > 0 ? extras.Get <string>(0) : null; var folder = await db.Directory.TryOpenAsync(path, ct : ct); if (folder == null) { Program.Error(log, $"# Directory /{string.Join("/", path)} does not exist"); return; } // are there any subdirectories ? var subDirs = await folder.TryListAsync(db, ct); if (subDirs != null && subDirs.Count > 0) { //TODO: "-r" flag ? Program.Error(log, $"# Cannot remove /{string.Join("/", path)} because it still contains {subDirs.Count:N0} sub-directorie(s)"); } //TODO: ask for confirmation? await folder.RemoveAsync(db, ct); Program.Success(log, $"Deleted directory /{string.Join("/", path)}"); }
public static IVarTuple Splice(IVarTuple tuple, Range range) { Contract.Requires(tuple != null); int count = tuple.Count; (int start, int len) = range.GetOffsetAndLength(count); if (len == 0) { return(STuple.Empty); } if (start == 0 && len == count) { return(tuple); } switch (len) { case 1: return(new ListTuple <object?>(new[] { tuple[start] })); case 2: return(new ListTuple <object?>(new[] { tuple[start], tuple[start + 1] })); default: { var items = new object?[len]; //note: can be slow for tuples using linked-lists, but hopefully they will have their own Slice implementation... int q = start; for (int p = 0; p < items.Length; p++) { items[p] = tuple[q++]; } return(new ListTuple <object?>(items.AsMemory())); } } }
/// <summary>Default (non-optimized) implementation for ITuple.EndsWith()</summary> /// <param name="a">Larger tuple</param> /// <param name="b">Smaller tuple</param> /// <returns>True if <paramref name="a"/> starts with (or is equal to) <paramref name="b"/></returns> public static bool EndsWith(IVarTuple a, IVarTuple b) { Contract.Debug.Requires(a != null && b != null); if (object.ReferenceEquals(a, b)) { return(true); } int an = a.Count; int bn = b.Count; if (bn > an) { return(false); } if (bn == 0) { return(true); // note: 'an' can only be 0 because of previous test } int offset = an - bn; for (int i = 0; i < bn; i++) { if (!object.Equals(a[offset + i], b[i])) { return(false); } } return(true); }
private static void LogCommand(string prm, IVarTuple extras, TextWriter log) { switch (prm.ToLowerInvariant()) { case "on": { LogEnabled = true; log.WriteLine("# Logging enabled"); break; } case "off": { LogEnabled = false; log.WriteLine("# Logging disabled"); break; } default: { log.WriteLine("# Logging is {0}", LogEnabled ? "ON" : "OFF"); break; } } }
/// <summary>Creates a new directory</summary> public static async Task CreateDirectory(string[] path, IVarTuple extras, IFdbDatabase db, TextWriter log, CancellationToken ct) { if (log == null) { log = Console.Out; } string layer = extras.Count > 0 ? extras.Get <string>(0) : null; log.WriteLine($"# Creating directory {String.Join("/", path)} with layer '{layer}'"); var folder = await db.Directory.TryOpenAsync(db, path, ct : ct); if (folder != null) { log.WriteLine($"- Directory {string.Join("/", path)} already exists!"); return; } folder = await db.Directory.TryCreateAsync(db, path, Slice.FromString(layer), ct : ct); log.WriteLine($"- Created under {FdbKey.Dump(folder.GetPrefix())} [{folder.GetPrefix().ToHexaString(' ')}]"); // look if there is already stuff under there var stuff = await db.ReadAsync((tr) => tr.GetRange(folder.Keys.ToRange()).FirstOrDefaultAsync(), ct : ct); if (stuff.Key.IsPresent) { Program.Error(log, $"CAUTION: There is already some data under {string.Join("/", path)} !"); Program.Error(log, $" {FdbKey.Dump(stuff.Key)} = {stuff.Value:V}"); } }
public PrefixedTuple(Slice prefix, IVarTuple items) { Contract.Debug.Requires(!prefix.IsNull && items != null); m_prefix = prefix; m_items = items; }
/// <summary>Remove a directory and all its data</summary> public static async Task RemoveDirectory(string[] path, IVarTuple extras, IFdbDatabase db, TextWriter log, CancellationToken ct) { if (log == null) { log = Console.Out; } string layer = extras.Count > 0 ? extras.Get <string>(0) : null; var folder = await db.Directory.TryOpenAsync(path, ct : ct); if (folder == null) { log.WriteLine("# Directory {0} does not exist", string.Join("/", path)); return; } // are there any subdirectories ? var subDirs = await folder.TryListAsync(db, ct); if (subDirs != null && subDirs.Count > 0) { //TODO: "-r" flag ? log.WriteLine("# Cannot remove {0} because it still contains {1} sub-directorie(s)", string.Join("/", path), subDirs.Count); } //TODO: ask for confirmation? log.WriteLine("# Deleting directory {0} ...", String.Join("/", path)); await folder.RemoveAsync(db, ct); log.WriteLine("# Gone!"); }
/// <summary>Create a new list tuple by merging the items of three tuples together</summary> public ListTuple(IVarTuple a, IVarTuple b, IVarTuple c) { Contract.NotNull(a, nameof(a)); Contract.NotNull(b, nameof(b)); Contract.NotNull(c, nameof(c)); int nA = a.Count; int nB = b.Count; int nC = c.Count; m_offset = 0; m_count = nA + nB + nC; m_items = new object[m_count]; if (nA > 0) { a.CopyTo(m_items, 0); } if (nB > 0) { b.CopyTo(m_items, nA); } if (nC > 0) { c.CopyTo(m_items, nA + nB); } }
public static T Last <T>(this IVarTuple tuple) { #if USE_RANGE_API return(tuple.Get <T>(^ 1)); #else return(tuple.Get <T>(-1)); #endif }
/// <summary>Test if the end of current tuple is equal to another tuple</summary> /// <param name="left">Larger tuple</param> /// <param name="right">Smaller tuple</param> /// <returns>True if the end of <paramref name="left"/> is equal to <paramref name="right"/> or if both tuples are identical</returns> public static bool EndsWith(this IVarTuple left, IVarTuple right) { Contract.NotNull(left, nameof(left)); Contract.NotNull(right, nameof(right)); //REVIEW: move this on ITuple interface ? return(TupleHelpers.EndsWith(left, right)); }
/// <summary>Append a new value at the end of an existing tuple</summary> public LinkedTuple(IVarTuple head, T tail) { Contract.NotNull(head); this.Head = head; this.Tail = tail; this.Depth = head.Count; }
/// <summary>Returns a typed version of a tuple of size 2</summary> /// <typeparam name="T1">Expected type of the first element</typeparam> /// <typeparam name="T2">Expected type of the second element</typeparam> /// <param name="tuple">Tuple that must be of size 2</param> /// <returns>Equivalent tuple, with its elements converted to the specified types</returns> public static ValueTuple <T1, T2> As <T1, T2>(this IVarTuple tuple) { tuple.OfSize(2); return( tuple.Get <T1>(0), tuple.Get <T2>(1) ); }
public static void Deconstruct <T1, T2, T3, T4, T5>(this IVarTuple value, [MaybeNull] out T1 item1, [MaybeNull] out T2 item2, [MaybeNull] out T3 item3, [MaybeNull] out T4 item4, [MaybeNull] out T5 item5) { value.OfSize(5); item1 = value.Get <T1>(0) !; item2 = value.Get <T2>(1) !; item3 = value.Get <T3>(2) !; item4 = value.Get <T4>(3) !; item5 = value.Get <T5>(4) !; }
/// <summary>Returns a typed version of a tuple of size 3</summary> /// <typeparam name="T1">Expected type of the first element</typeparam> /// <typeparam name="T2">Expected type of the second element</typeparam> /// <typeparam name="T3">Expected type of the third element</typeparam> /// <param name="tuple">Tuple that must be of size 3</param> /// <returns>Equivalent tuple, with its elements converted to the specified types</returns> public static ValueTuple <T1, T2, T3> As <T1, T2, T3>([NotNull] this IVarTuple tuple) { tuple.OfSize(3); return( tuple.Get <T1>(0), tuple.Get <T2>(1), tuple.Get <T3>(2) ); }
public static void Deconstruct <T1, T2, T3, T4, T5>(this IVarTuple value, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5) { value.OfSize(5); item1 = value.Get <T1>(0); item2 = value.Get <T2>(1); item3 = value.Get <T3>(2); item4 = value.Get <T4>(3); item5 = value.Get <T5>(4); }
public static async Task Dump(string[] path, string output, IVarTuple extras, IFdbDatabase db, TextWriter log, CancellationToken ct) { // look if there is something under there var folder = await db.Directory.TryOpenAsync(db, path, ct : ct); if (folder == null) { Program.Comment(log, $"# Directory {String.Join("/", path)} does not exist"); return; } //TODO: if file already exists, ask confirmation before overriding? output = Path.GetFullPath(output); File.Delete(output); using (var fs = new FileStream(output, FileMode.Create, FileAccess.Write, FileShare.Read, 64 * 1024)) using (var sw = new StreamWriter(fs, Encoding.UTF8, 32 * 1024)) { Program.Comment(log, $"# Dumping content of {FdbKey.Dump(folder.GetPrefix())} [{folder.GetPrefix().ToHexaString(' ')}] to {output}"); long bytes = 0; var kr = new[] { '|', '/', '-', '\\' }; int p = 0; var count = await Fdb.Bulk.ExportAsync( db, folder.ToRange(), (batch, offset, _ct) => { if (log == Console.Out) { log.Write($"\r{kr[(p++) % kr.Length]} {bytes:N0} bytes"); } foreach (var kv in batch) { bytes += kv.Key.Count + kv.Value.Count; sw.WriteLine("{0} = {1:V}", FdbKey.Dump(folder.ExtractKey(kv.Key)), kv.Value); } ct.ThrowIfCancellationRequested(); return(sw.FlushAsync()); }, ct ); if (log == Console.Out) { log.Write("\r"); } if (count > 0) { Program.Success(log, $"Found {count:N0} keys ({bytes:N0} bytes)"); } else { Program.StdOut(log, "Folder is empty."); } } }
public JoinedTuple(IVarTuple head, IVarTuple tail) { Contract.NotNull(head, nameof(head)); Contract.NotNull(tail, nameof(tail)); this.Head = head; this.Tail = tail; m_split = head.Count; m_count = m_split + tail.Count; }
/// <summary>Helper to copy the content of a tuple at a specific position in an array</summary> /// <returns>Updated offset just after the last element of the copied tuple</returns> public static int CopyTo([NotNull] IVarTuple tuple, [NotNull] object[] array, int offset) { Contract.Requires(tuple != null && array != null && offset >= 0); foreach (var item in tuple) { array[offset++] = item; } return(offset); }
/// <summary>Returns a typed version of a tuple of size 4</summary> /// <typeparam name="T1">Expected type of the first element</typeparam> /// <typeparam name="T2">Expected type of the second element</typeparam> /// <typeparam name="T3">Expected type of the third element</typeparam> /// <typeparam name="T4">Expected type of the fourth element</typeparam> /// <param name="tuple">Tuple that must be of size 4</param> /// <returns>Equivalent tuple, with its elements converted to the specified types</returns> public static ValueTuple <T1, T2, T3, T4> As <T1, T2, T3, T4>(this IVarTuple tuple) { tuple.OfSize(4); return( tuple.Get <T1>(0), tuple.Get <T2>(1), tuple.Get <T3>(2), tuple.Get <T4>(3) ); }
public PrefixedTuple Concat(IVarTuple tuple) { Contract.NotNull(tuple); if (tuple.Count == 0) { return(this); } return(new PrefixedTuple(m_prefix, m_items.Concat(tuple))); }
/// <summary>Returns a typed version of a tuple of size 5</summary> /// <typeparam name="T1">Expected type of the first element</typeparam> /// <typeparam name="T2">Expected type of the second element</typeparam> /// <typeparam name="T3">Expected type of the third element</typeparam> /// <typeparam name="T4">Expected type of the fourth element</typeparam> /// <typeparam name="T5">Expected type of the fifth element</typeparam> /// <param name="tuple">Tuple that must be of size 5</param> /// <returns>Equivalent tuple, with its elements converted to the specified types</returns> public static ValueTuple <T1, T2, T3, T4, T5> As <T1, T2, T3, T4, T5>([NotNull] this IVarTuple tuple) { tuple.OfSize(5); return( tuple.Get <T1>(0), tuple.Get <T2>(1), tuple.Get <T3>(2), tuple.Get <T4>(3), tuple.Get <T5>(4) ); }
public static void Deconstruct <T1, T2, T3, T4, T5, T6, T7>(this IVarTuple value, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7) { value.OfSize(7); item1 = value.Get <T1>(0); item2 = value.Get <T2>(1); item3 = value.Get <T3>(2); item4 = value.Get <T4>(3); item5 = value.Get <T5>(4); item6 = value.Get <T6>(5); item7 = value.Get <T7>(6); }
protected override FdbDirectoryLayer GetLayerForPath(IVarTuple relativeLocation) { if (relativeLocation.Count == 0) { // Forward all actions on the Partition itself (empty path) to its parent's DL return(this.ParentDirectoryLayer); } else { // For everything else, use the Partition's DL return(this.DirectoryLayer); } }
public static void Deconstruct <T1, T2, T3, T4, T5, T6, T7>(this IVarTuple value, [MaybeNull] out T1 item1, [MaybeNull] out T2 item2, [MaybeNull] out T3 item3, [MaybeNull] out T4 item4, [MaybeNull] out T5 item5, [MaybeNull] out T6 item6, [MaybeNull] out T7 item7) { value.OfSize(7); item1 = value.Get <T1>(0) !; item2 = value.Get <T2>(1) !; item3 = value.Get <T3>(2) !; item4 = value.Get <T4>(3) !; item5 = value.Get <T5>(4) !; item6 = value.Get <T6>(5) !; item7 = value.Get <T7>(6) !; }