protected virtual void Dispose(bool disposing) { if (!m_disposed) { m_disposed = true; if (disposing && m_owner) { m_database.Dispose(); } } }
public void SetDatabase(IFdbDatabase db, Exception e) { this.Db = db; this.Error = e; var tcs = Volatile.Read(ref this.InitTask); if (db == null) { if (e != null) { tcs?.TrySetException(e); this.DbTask = Task.FromException <IFdbDatabase>(e); } else { tcs?.TrySetCanceled(); this.DbTask = Task.FromException <IFdbDatabase>(new InvalidOperationException("There is no database available at this time.")); } this.IsAvailable = false; } else { if (tcs == null || !tcs.TrySetResult(db)) { #if DEBUG if (System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Break(); } #endif db.Dispose(); return; } this.DbTask = Task.FromResult(db); this.IsAvailable = true; } }
private static async Task MainAsync(string[] args, CancellationToken cancel) { #region Options Parsing... string clusterFile = null; var partition = FdbPath.Root; bool showHelp = false; int timeout = 30; int maxRetries = 10; string execCommand = null; var opts = new OptionSet() { { "c|C|connfile=", "The path of a file containing the connection string for the FoundationDB cluster.", v => clusterFile = v }, { "p|partition=", "The name of the database partition to open.", v => partition = FdbPath.Parse(v.Trim()) }, { "t|timeout=", "Default timeout (in seconds) for failed transactions.", (int v) => timeout = v }, { "r|retries=", "Default max retry count for failed transactions.", (int v) => maxRetries = v }, { "exec=", "Execute this command, and exits immediately.", v => execCommand = v }, { "h|help", "Show this help and exit.", v => showHelp = v != null } }; var extra = opts.Parse(args); if (showHelp) { //TODO! opts.WriteOptionDescriptions(Console.Out); return; } string startCommand = null; if (!string.IsNullOrEmpty(execCommand)) { startCommand = execCommand; } else if (extra.Count > 0) { // the remainder of the command line will be the first command to execute startCommand = String.Join(" ", extra); } #endregion bool stop = false; Db = null; try { var cnxOptions = new FdbConnectionOptions { ClusterFile = clusterFile, Root = partition }; Db = await ChangeDatabase(cnxOptions, cancel); Db.DefaultTimeout = Math.Max(0, timeout) * 1000; Db.DefaultRetryLimit = Math.Max(0, maxRetries); StdOut("Using API v" + Fdb.ApiVersion + " (max " + Fdb.GetMaxApiVersion() + ")", ConsoleColor.Gray); StdOut("Cluster file: " + (clusterFile ?? "<default>"), ConsoleColor.Gray); StdOut(""); StdOut("FoundationDB Shell menu:"); StdOut("\tcd\tChange the current directory"); StdOut("\tdir\tList the sub-directories the current directory"); StdOut("\tshow\tShow the content of the current directory"); StdOut("\ttree\tShow all the directories under the current directory"); StdOut("\tsampling\tDisplay statistics on random shards from the database"); StdOut("\tcoordinators\tShow the current coordinators for the cluster"); //StdOut("\thelp\tShow all the commands"); StdOut("\tquit\tQuit"); StdOut(""); try { var cf = await Fdb.System.GetCoordinatorsAsync(Db, cancel); Description = cf.Description; StdOut("Ready...", ConsoleColor.DarkGreen); } catch (Exception e) { StdErr("Failed to get coordinators state from cluster: " + e.Message, ConsoleColor.DarkRed); Description = "???"; } StdOut(""); var le = new LineEditor("FDBShell"); string[] cmds = new string[] { "cd", "clear", "coordinators", "count", "dir", "dump", "exit", "gc", "help", "layer", "map", "mem", "mkdir", "mv", "partition", "pwd", "quit", "ren", "rmdir", "sampling", "shards", "show", "status", "topology", "tree", "version", "wide", }; le.AutoCompleteEvent = (txt, pos) => { string[] res; int p = txt.IndexOf(' '); if (p > 0) { string cmd = txt.Substring(0, p); string arg = txt.Substring(p + 1).Trim(); if (cmd == "cd" || cmd == "rmdir") { // handle completion for directories // txt: "cd foo" => prefix = "foo" // txt: "cd foobar/b" => prefix = "b" bool hasLeadingSlash = arg.EndsWith("/"); var path = FdbPath.Parse(hasLeadingSlash ? (arg + "!") : arg); var parent = path.Count > 1 ? path.GetParent() : path.IsAbsolute ? FdbPath.Root : FdbPath.Empty; string search = hasLeadingSlash ? "" : path.Name; var subdirs = RunAsyncCommand((db, log, ct) => AutoCompleteDirectories(CombinePath(CurrentDirectoryPath, parent.ToString()), db, log, ct), cancel).GetAwaiter().GetResult(); if (!subdirs.HasValue || subdirs.Value == null) { return(new LineEditor.Completion(txt, null)); } res = subdirs.Value .Where(s => s.StartsWith(search, StringComparison.Ordinal)) .Select(s => (cmd + " " + parent[s]).Substring(txt.Length)) .ToArray(); if (res.Length == 1 && res[0] == string.Empty) { // someone was at "cd /Foo/Bar", pressed TAB again, and there is no other match // => we interpret it as "want to go in the sub-folder res = new[] { "/" }; // add a "slash" } return(new LineEditor.Completion(txt, res)); } // unknown command return(new LineEditor.Completion(txt, null)); } // list of commands res = cmds .Where(cmd => cmd.StartsWith(txt, StringComparison.OrdinalIgnoreCase)) .Select(cmd => cmd.Substring(txt.Length)) .ToArray(); return(new LineEditor.Completion(txt, res)); }; le.TabAtStartCompletes = true; string prompt = null; void UpdatePrompt(FdbPath path) { prompt = $"[fdb:{Description} {path.ToString()}]# "; } le.PromptColor = ConsoleColor.Cyan; UpdatePrompt(CurrentDirectoryPath); while (!stop) { string s; if (startCommand != null) { s = startCommand; startCommand = null; } else { s = startCommand ?? le.Edit(prompt, ""); } if (s == null) { break; } //TODO: we need a tokenizer that recognizes binary keys, tuples, escaped paths, etc... var tokens = Tokenize(s); string cmd = tokens.Count > 0 ? tokens.Get <string>(0) : string.Empty; var extras = tokens.Count > 1 ? tokens.Substring(1) : STuple.Empty; var trimmedCommand = cmd.Trim().ToLowerInvariant(); try { switch (trimmedCommand) { case "": { continue; } case "log": { string prm = PopParam(ref extras); LogCommand(prm, extras, Console.Out); break; } case "version": { await VersionCommand(extras, clusterFile, Console.Out, cancel); break; } case "tree": { string prm = PopParam(ref extras); var path = CombinePath(CurrentDirectoryPath, prm); await RunAsyncCommand((db, log, ct) => BasicCommands.Tree(path, extras, db, log, ct), cancel); break; } case "map": { string prm = PopParam(ref extras); var path = CombinePath(CurrentDirectoryPath, prm); await RunAsyncCommand((db, log, ct) => BasicCommands.Map(path, extras, db, log, ct), cancel); break; } case "dir": case "ls": { string prm = PopParam(ref extras); var path = CombinePath(CurrentDirectoryPath, prm); await RunAsyncCommand((db, log, ct) => BasicCommands.Dir(path, extras, BasicCommands.DirectoryBrowseOptions.Default, db, log, ct), cancel); break; } case "ll": { string prm = PopParam(ref extras); var path = CombinePath(CurrentDirectoryPath, prm); await RunAsyncCommand((db, log, ct) => BasicCommands.Dir(path, extras, BasicCommands.DirectoryBrowseOptions.ShowCount, db, log, ct), cancel); break; } case "count": { string prm = PopParam(ref extras); var path = CombinePath(CurrentDirectoryPath, prm); await RunAsyncCommand((db, log, ct) => BasicCommands.Count(path, extras, db, log, ct), cancel); break; } case "show": case "top": { await RunAsyncCommand((db, log, ct) => BasicCommands.Show(CurrentDirectoryPath, extras, false, db, log, ct), cancel); break; } case "last": { await RunAsyncCommand((db, log, ct) => BasicCommands.Show(CurrentDirectoryPath, extras, true, db, log, ct), cancel); break; } case "dump": { string output = PopParam(ref extras); if (string.IsNullOrEmpty(output)) { StdErr("You must specify a target file path.", ConsoleColor.Red); break; } await RunAsyncCommand((db, log, ct) => BasicCommands.Dump(CurrentDirectoryPath, output, extras, db, log, ct), cancel); break; } case "cd": case "pwd": { string prm = PopParam(ref extras); if (!string.IsNullOrEmpty(prm)) { var newPath = CombinePath(CurrentDirectoryPath, prm); var res = await RunAsyncCommand( (db, log, ct) => db.ReadAsync(tr => BasicCommands.TryOpenCurrentDirectoryAsync(tr, newPath), ct), cancel ); if (res.Failed) { StdErr($"# Failed to open Directory {newPath}: {res.Error.Message}", ConsoleColor.Red); Console.Beep(); } else if (res.Value == null) { StdOut($"# Directory {newPath} does not exist!", ConsoleColor.Red); Console.Beep(); } else { CurrentDirectoryPath = newPath; UpdatePrompt(CurrentDirectoryPath); } } else { var res = await RunAsyncCommand( (db, log, ct) => db.ReadAsync(tr => BasicCommands.TryOpenCurrentDirectoryAsync(tr, CurrentDirectoryPath), ct), cancel ); if (res.Failed) { StdErr($"# Failed to query Directory {Program.CurrentDirectoryPath}: {res.Error.Message}", ConsoleColor.Red); } else if (res.Value == null) { StdOut($"# Directory {Program.CurrentDirectoryPath} does not exist anymore"); } } break; } case "mkdir": case "md": { // "mkdir DIRECTORYNAME" string prm = PopParam(ref extras); if (!string.IsNullOrEmpty(prm)) { var path = CombinePath(CurrentDirectoryPath, prm); await RunAsyncCommand((db, log, ct) => BasicCommands.CreateDirectory(path, extras, db, log, ct), cancel); } break; } case "rmdir": { // "rmdir DIRECTORYNAME" string prm = PopParam(ref extras); if (!string.IsNullOrEmpty(prm)) { var path = CombinePath(CurrentDirectoryPath, prm); await RunAsyncCommand((db, log, ct) => BasicCommands.RemoveDirectory(path, extras, db, log, ct), cancel); } break; } case "mv": case "ren": { // "mv SOURCE DESTINATION" string prm = PopParam(ref extras); var srcPath = CombinePath(CurrentDirectoryPath, prm); var dstPath = CombinePath(CurrentDirectoryPath, extras.Get <string>(0)); await RunAsyncCommand((db, log, ct) => BasicCommands.MoveDirectory(srcPath, dstPath, extras.Substring(1), db, log, ct), cancel); break; } case "get": { // "get KEY" if (extras.Count == 0) { StdErr("You must specify a key to read.", ConsoleColor.Red); break; } await RunAsyncCommand((db, log, ct) => BasicCommands.Get(CurrentDirectoryPath, extras, db, log, ct), cancel); break; } case "clear": { // "clear KEY" if (extras.Count == 0) { StdErr("You must specify a key to clear.", ConsoleColor.Red); break; } await RunAsyncCommand((db, log, ct) => BasicCommands.Clear(CurrentDirectoryPath, extras, db, log, ct), cancel); break; } case "clearrange": { // "clear *" or "clear FROM TO" if (extras.Count == 0) { StdErr("You must specify either '*', a prefix, or a key range.", ConsoleColor.Red); break; } await RunAsyncCommand((db, log, ct) => BasicCommands.ClearRange(CurrentDirectoryPath, extras, db, log, ct), cancel); break; } case "layer": { string prm = PopParam(ref extras); if (string.IsNullOrEmpty(prm)) { // displays the layer id of the current folder await RunAsyncCommand((db, log, ct) => BasicCommands.ShowDirectoryLayer(CurrentDirectoryPath, extras, db, log, ct), cancel); } else { // change the layer id of the current folder prm = prm.Trim(); // double or single quotes can be used to escape the value if (prm.Length >= 2 && (prm.StartsWith("'") && prm.EndsWith("'")) || (prm.StartsWith("\"") && prm.EndsWith("\""))) { prm = prm.Substring(1, prm.Length - 2); } await RunAsyncCommand((db, log, ct) => BasicCommands.ChangeDirectoryLayer(CurrentDirectoryPath, prm, extras, db, log, ct), cancel); } break; } case "mkpart": { // "mkpart PARTITIONNAME" string prm = PopParam(ref extras); if (!string.IsNullOrEmpty(prm)) { var path = CombinePath(CurrentDirectoryPath, prm); await RunAsyncCommand((db, log, ct) => BasicCommands.CreateDirectory(path, STuple.Create(FdbDirectoryPartition.LayerId).Concat(extras), db, log, ct), cancel); } break; } case "topology": { await RunAsyncCommand((db, log, ct) => BasicCommands.Topology(null, extras, db, log, ct), cancel); break; } case "shards": { string prm = PopParam(ref extras); var path = CombinePath(CurrentDirectoryPath, prm); await RunAsyncCommand((db, log, ct) => BasicCommands.Shards(path, extras, db, log, ct), cancel); break; } case "sampling": { string prm = PopParam(ref extras); var path = CombinePath(CurrentDirectoryPath, prm); await RunAsyncCommand((db, log, ct) => BasicCommands.Sampling(path, extras, db, log, ct), cancel); break; } case "coordinators": { await RunAsyncCommand((db, log, ct) => CoordinatorsCommand(db, log, ct), cancel); break; } case "partition": { string prm = PopParam(ref extras); if (string.IsNullOrEmpty(prm)) { StdOut($"# Current partition is {partition}"); //TODO: browse existing partitions ? break; } var newPartition = FdbPath.Parse(prm.Trim()); IFdbDatabase newDb = null; try { var options = new FdbConnectionOptions { ClusterFile = clusterFile, Root = newPartition }; newDb = await ChangeDatabase(options, cancel); } catch (Exception) { newDb?.Dispose(); newDb = null; throw; } finally { if (newDb != null) { if (Db != null) { Db.Dispose(); Db = null; } Db = newDb; partition = newPartition; StdOut($"# Changed partition to {partition}"); } } break; } case "q": case "x": case "quit": case "exit": case "bye": { stop = true; break; } case "gc": { long before = GC.GetTotalMemory(false); Console.Write("Collecting garbage..."); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); StdOut(" Done"); long after = GC.GetTotalMemory(false); StdOut("- before = " + before.ToString("N0")); StdOut("- after = " + after.ToString("N0")); StdOut("- delta = " + (before - after).ToString("N0")); break; } case "mem": { StdOut("Memory usage:"); StdOut("- Managed Mem : " + GC.GetTotalMemory(false).ToString("N0")); //TODO: how do we get these values on Linux/Mac? #if !NETCOREAPP StdOut("- Working Set : " + PerfCounters.WorkingSet.NextValue().ToString("N0") + " (peak " + PerfCounters.WorkingSetPeak.NextValue().ToString("N0") + ")"); StdOut("- Virtual Bytes: " + PerfCounters.VirtualBytes.NextValue().ToString("N0") + " (peak " + PerfCounters.VirtualBytesPeak.NextValue().ToString("N0") + ")"); StdOut("- Private Bytes: " + PerfCounters.PrivateBytes.NextValue().ToString("N0")); StdOut("- BytesInAlHeap: " + PerfCounters.ClrBytesInAllHeaps.NextValue().ToString("N0")); #endif break; } case "wide": { try { Console.WindowWidth = 160; } catch (Exception e) { StdErr("Failed to change console width: " + e.Message, ConsoleColor.DarkRed); } break; } case "status": case "wtf": { var result = await RunAsyncCommand((_, log, ct) => FdbCliCommands.RunFdbCliCommand("status details", null, clusterFile, log, ct), cancel); if (result.Failed) { break; } if (result.Value.ExitCode != 0) { StdErr($"# fdbcli exited with code {result.Value.ExitCode}", ConsoleColor.DarkRed); StdOut("> StdErr:", ConsoleColor.DarkGray); StdOut(result.Value.StdErr); StdOut("> StdOut:", ConsoleColor.DarkGray); } StdOut(result.Value.StdOut); break; } default: { StdErr($"Unknown command : '{trimmedCommand}'", ConsoleColor.Red); break; } } } catch (Exception e) { StdErr($"Failed to execute command '{trimmedCommand}': " + e.Message, ConsoleColor.Red); #if DEBUG StdErr(e.ToString(), ConsoleColor.DarkRed); #endif } if (!string.IsNullOrEmpty(execCommand)) { // only run one command, and then exit break; } } } finally { Program.Db?.Dispose(); } }
private static async Task MainAsync(string[] args, CancellationToken cancel) { #region Options Parsing... string clusterFile = null; var dbName = "DB"; var partition = new string[0]; bool showHelp = false; int timeout = 30; int maxRetries = 10; string execCommand = null; var opts = new OptionSet() { { "c|connfile=", "The path of a file containing the connection string for the FoundationDB cluster.", v => clusterFile = v }, { "p|partition=", "The name of the database partition to open.", v => partition = v.Trim().Split('/') }, { "t|timeout=", "Default timeout (in seconds) for failed transactions.", (int v) => timeout = v }, { "r|retries=", "Default max retry count for failed transactions.", (int v) => maxRetries = v }, { "exec=", "Execute this command, and exits immediately.", v => execCommand = v }, { "h|help", "Show this help and exit.", v => showHelp = v != null } }; var extra = opts.Parse(args); if (showHelp) { //TODO! opts.WriteOptionDescriptions(Console.Out); return; } string startCommand = null; if (!string.IsNullOrEmpty(execCommand)) { startCommand = execCommand; } else if (extra.Count > 0) { // the remainder of the command line will be the first command to execute startCommand = String.Join(" ", extra); } #endregion bool stop = false; Db = null; try { Db = await ChangeDatabase(clusterFile, dbName, partition, cancel); Db.DefaultTimeout = Math.Max(0, timeout) * 1000; Db.DefaultRetryLimit = Math.Max(0, maxRetries); Console.WriteLine("Using API v" + Fdb.ApiVersion + " (max " + Fdb.GetMaxApiVersion() + ")"); Console.WriteLine("Cluster file: " + (clusterFile ?? "<default>")); Console.WriteLine(); Console.WriteLine("FoundationDB Shell menu:"); Console.WriteLine("\tdir\tShow the content of the current directory"); Console.WriteLine("\ttree\tShow all the directories under the current directory"); Console.WriteLine("\tsampling\tDisplay statistics on random shards from the database"); Console.WriteLine("\tcoordinators\tShow the current coordinators for the cluster"); Console.WriteLine("\tmem\tShow memory usage statistics"); Console.WriteLine("\tgc\tTrigger garbage collection"); Console.WriteLine("\tquit\tQuit"); Console.WriteLine("Ready..."); var le = new LineEditor("FDBShell"); string[] cmds = new string[] { "cd", "coordinators", "count", "dir", "exit", "gc", "help", "layer", "map", "mem", "mkdir", "mv", "partition", "pwd", "quit", "ren", "rmdir", "sampling", "shards", "show", "status", "topology", "tree", "version", "wide", }; le.AutoCompleteEvent = (txt, pos) => { string[] res; int p = txt.IndexOf(' '); if (p > 0) { string cmd = txt.Substring(0, p); string arg = txt.Substring(p + 1); if (cmd == "cd") { // handle completion for directories // txt: "cd foo" => prefix = "foo" // txt: "cd foobar/b" => prefix = "b" string path = CurrentDirectoryPath; string prefix = ""; string search = arg; p = arg.LastIndexOf('/'); if (p > 0) { path = Path.Combine(path, arg.Substring(0, p)); search = arg.Substring(p + 1); prefix = arg.Substring(0, p + 1); } var subdirs = RunAsyncCommand((db, log, ct) => AutoCompleteDirectories(path, db, log, ct), cancel).GetAwaiter().GetResult(); if (!subdirs.HasValue || subdirs.Value == null) { return(new LineEditor.Completion(txt, null)); } res = subdirs.Value .Where(s => s.StartsWith(search, StringComparison.Ordinal)) .Select(s => (cmd + " " + prefix + s).Substring(txt.Length)) .ToArray(); return(new LineEditor.Completion(txt, res)); } // unknown command return(new LineEditor.Completion(txt, null)); } // list of commands res = cmds .Where(cmd => cmd.StartsWith(txt, StringComparison.OrdinalIgnoreCase)) .Select(cmd => cmd.Substring(txt.Length)) .ToArray(); return(new LineEditor.Completion(txt, res)); }; le.TabAtStartCompletes = true; string prompt = null; Action <string> updatePrompt = (path) => { prompt = String.Format("fdb:{0}> ", path); }; updatePrompt(CurrentDirectoryPath); while (!stop) { string s = startCommand != null ? startCommand : le.Edit(prompt, ""); startCommand = null; if (s == null) { break; } var tokens = s.Trim().Split(new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries); string cmd = tokens.Length > 0 ? tokens[0] : String.Empty; string prm = tokens.Length > 1 ? tokens[1] : String.Empty; var extras = tokens.Length > 2 ? FdbTuple.CreateRange <string>(tokens.Skip(2)) : FdbTuple.Empty; var trimmedCommand = cmd.Trim().ToLowerInvariant(); switch (trimmedCommand) { case "": { continue; } case "log": { LogCommand(prm, Console.Out); break; } case "version": { await VersionCommand(prm, clusterFile, Console.Out, cancel); break; } case "tree": { var path = ParsePath(CombinePath(CurrentDirectoryPath, prm)); await RunAsyncCommand((db, log, ct) => BasicCommands.Tree(path, extras, db, log, ct), cancel); break; } case "map": { var path = ParsePath(CombinePath(CurrentDirectoryPath, prm)); await RunAsyncCommand((db, log, ct) => BasicCommands.Map(path, extras, db, log, ct), cancel); break; } case "dir": case "ls": { var path = ParsePath(CombinePath(CurrentDirectoryPath, prm)); await RunAsyncCommand((db, log, ct) => BasicCommands.Dir(path, extras, BasicCommands.DirectoryBrowseOptions.Default, db, log, ct), cancel); break; } case "ll": { var path = ParsePath(CombinePath(CurrentDirectoryPath, prm)); await RunAsyncCommand((db, log, ct) => BasicCommands.Dir(path, extras, BasicCommands.DirectoryBrowseOptions.ShowCount, db, log, ct), cancel); break; } case "count": { var path = ParsePath(CombinePath(CurrentDirectoryPath, prm)); await RunAsyncCommand((db, log, ct) => BasicCommands.Count(path, extras, db, log, ct), cancel); break; } case "show": case "top": { var path = ParsePath(CurrentDirectoryPath); await RunAsyncCommand((db, log, ct) => BasicCommands.Show(path, extras, false, db, log, ct), cancel); break; } case "last": { var path = ParsePath(CurrentDirectoryPath); await RunAsyncCommand((db, log, ct) => BasicCommands.Show(path, extras, true, db, log, ct), cancel); break; } case "cd": case "pwd": { if (!string.IsNullOrEmpty(prm)) { var newPath = CombinePath(CurrentDirectoryPath, prm); var res = await RunAsyncCommand((db, log, ct) => BasicCommands.TryOpenCurrentDirectoryAsync(ParsePath(newPath), db, ct), cancel); if (res == null) { Console.WriteLine("# Directory {0} does not exist!", newPath); Console.Beep(); } else { CurrentDirectoryPath = newPath; updatePrompt(CurrentDirectoryPath); } } else { var res = await RunAsyncCommand((db, log, ct) => BasicCommands.TryOpenCurrentDirectoryAsync(ParsePath(CurrentDirectoryPath), db, ct), cancel); if (res.GetValueOrDefault() == null) { Console.WriteLine("# Directory {0} does not exist anymore", CurrentDirectoryPath); } else { Console.WriteLine("# {0}", res); } } break; } case "mkdir": case "md": { // "mkdir DIRECTORYNAME" if (!string.IsNullOrEmpty(prm)) { var path = ParsePath(CombinePath(CurrentDirectoryPath, prm)); await RunAsyncCommand((db, log, ct) => BasicCommands.CreateDirectory(path, extras, db, log, ct), cancel); } break; } case "rmdir": { // "rmdir DIRECTORYNAME" if (!string.IsNullOrEmpty(prm)) { var path = ParsePath(CombinePath(CurrentDirectoryPath, prm)); await RunAsyncCommand((db, log, ct) => BasicCommands.RemoveDirectory(path, extras, db, log, ct), cancel); } break; } case "mv": case "ren": { // "mv SOURCE DESTINATION" var srcPath = ParsePath(CombinePath(CurrentDirectoryPath, prm)); var dstPath = ParsePath(CombinePath(CurrentDirectoryPath, extras.Get <string>(0))); await RunAsyncCommand((db, log, ct) => BasicCommands.MoveDirectory(srcPath, dstPath, extras.Substring(1), db, log, ct), cancel); break; } case "layer": { if (string.IsNullOrEmpty(prm)) { // displays the layer id of the current folder var path = ParsePath(CurrentDirectoryPath); await RunAsyncCommand((db, log, ct) => BasicCommands.ShowDirectoryLayer(path, extras, db, log, ct), cancel); } else { // change the layer id of the current folder prm = prm.Trim(); // double or single quotes can be used to escape the value if (prm.Length >= 2 && (prm.StartsWith("'") && prm.EndsWith("'")) || (prm.StartsWith("\"") && prm.EndsWith("\""))) { prm = prm.Substring(1, prm.Length - 2); } var path = ParsePath(CurrentDirectoryPath); await RunAsyncCommand((db, log, ct) => BasicCommands.ChangeDirectoryLayer(path, prm, extras, db, log, ct), cancel); } break; } case "mkpart": { // "mkpart PARTITIONNAME" if (!string.IsNullOrEmpty(prm)) { var path = ParsePath(CombinePath(CurrentDirectoryPath, prm)); await RunAsyncCommand((db, log, ct) => BasicCommands.CreateDirectory(path, FdbTuple.Create(FdbDirectoryPartition.LayerId).Concat(extras), db, log, ct), cancel); } break; } case "topology": { await RunAsyncCommand((db, log, ct) => BasicCommands.Topology(null, extras, db, log, ct), cancel); break; } case "shards": { var path = ParsePath(CombinePath(CurrentDirectoryPath, prm)); await RunAsyncCommand((db, log, ct) => BasicCommands.Shards(path, extras, db, log, ct), cancel); break; } case "sampling": { var path = ParsePath(CombinePath(CurrentDirectoryPath, prm)); await RunAsyncCommand((db, log, ct) => BasicCommands.Sampling(path, extras, db, log, ct), cancel); break; } case "coordinators": { await RunAsyncCommand((db, log, ct) => CoordinatorsCommand(db, log, ct), cancel); break; } case "partition": { if (string.IsNullOrEmpty(prm)) { Console.WriteLine("# Current partition is {0}", String.Join("/", partition)); //TODO: browse existing partitions ? break; } var newPartition = prm.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); IFdbDatabase newDb = null; try { newDb = await ChangeDatabase(clusterFile, dbName, newPartition, cancel); } catch (Exception) { if (newDb != null) { newDb.Dispose(); } newDb = null; throw; } finally { if (newDb != null) { if (Db != null) { Db.Dispose(); Db = null; } Db = newDb; partition = newPartition; Console.WriteLine("# Changed partition to {0}", partition); } } break; } case "q": case "x": case "quit": case "exit": case "bye": { stop = true; break; } case "gc": { long before = GC.GetTotalMemory(false); Console.Write("Collecting garbage..."); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); Console.WriteLine(" Done"); long after = GC.GetTotalMemory(false); Console.WriteLine("- before = " + before.ToString("N0")); Console.WriteLine("- after = " + after.ToString("N0")); Console.WriteLine("- delta = " + (before - after).ToString("N0")); break; } case "mem": { Console.WriteLine("Memory usage:"); Console.WriteLine("- Working Set : " + PerfCounters.WorkingSet.NextValue().ToString("N0") + " (peak " + PerfCounters.WorkingSetPeak.NextValue().ToString("N0") + ")"); Console.WriteLine("- Virtual Bytes: " + PerfCounters.VirtualBytes.NextValue().ToString("N0") + " (peak " + PerfCounters.VirtualBytesPeak.NextValue().ToString("N0") + ")"); Console.WriteLine("- Private Bytes: " + PerfCounters.PrivateBytes.NextValue().ToString("N0")); Console.WriteLine("- Managed Mem : " + GC.GetTotalMemory(false).ToString("N0")); Console.WriteLine("- BytesInAlHeap: " + PerfCounters.ClrBytesInAllHeaps.NextValue().ToString("N0")); break; } case "wide": { Console.WindowWidth = 160; break; } case "status": case "wtf": { var result = await RunAsyncCommand((_, log, ct) => FdbCliCommands.RunFdbCliCommand("status details", null, clusterFile, log, ct), cancel); if (result.HasFailed) { break; } if (result.Value.ExitCode != 0) { Console.WriteLine("# fdbcli exited with code {0}", result.Value.ExitCode); Console.WriteLine("> StdErr:"); Console.WriteLine(result.Value.StdErr); Console.WriteLine("> StdOut:"); } Console.WriteLine(result.Value.StdOut); break; } default: { Console.WriteLine(string.Format("Unknown command : '{0}'", trimmedCommand)); break; } } if (!string.IsNullOrEmpty(execCommand)) { // only run one command, and then exit break; } } } finally { if (Db != null) { Db.Dispose(); } } }