public void Test_Can_Serialize_Connection_Options()
        {
            var options = new FdbConnectionOptions();

            Assert.That(options.ToString(), Is.EqualTo("cluster_file=default"));

            options = new FdbConnectionOptions
            {
                ClusterFile = "X:\\some\\path\\to\\fdb.cluster",
                Root        = FdbPath.Parse("/Hello/World"),
            };
            Assert.That(options.ToString(), Is.EqualTo(@"cluster_file=X:\some\path\to\fdb.cluster; root=/Hello/World"));

            options = new FdbConnectionOptions
            {
                ClusterFile       = "X:\\some\\path\\to\\fdb.cluster",
                ReadOnly          = true,
                DefaultTimeout    = TimeSpan.FromSeconds(42.5),
                DefaultRetryLimit = 123,
                DataCenterId      = "AC/DC",
                MachineId         = "Marble Machine X"
            };
            Assert.That(options.ToString(), Is.EqualTo(@"cluster_file=X:\some\path\to\fdb.cluster; readonly; timeout=42.5; retry_limit=123; dc_id=AC/DC; machine_id=""Marble Machine X"""));

            options = new FdbConnectionOptions
            {
                ClusterFile    = "/etc/foundationdb/fdb.cluster",
                MachineId      = "James \"The Machine\" Wade",
                DefaultTimeout = TimeSpan.FromTicks((long)(Math.PI * TimeSpan.TicksPerSecond)),
            };
            Assert.That(options.ToString(), Is.EqualTo(@"cluster_file=/etc/foundationdb/fdb.cluster; timeout=3.1415926; machine_id=""James \""The Machine\"" Wade"""));
        }
Exemple #2
0
        private static FdbPath CombinePath(FdbPath parent, string children)
        {
            if (string.IsNullOrEmpty(children) || children == ".")
            {
                return(parent);
            }

            var p = FdbPath.Parse(children);

            if (!p.IsAbsolute)
            {
                p = parent[p];
            }
            if (HasIndirection(p))
            {
                p = RemoveIndirection(p);
            }
            return(p);
        }
        public void Test_FdbPath_Basics()
        {
            {
                var path = FdbPath.Relative("Foo");
                Assert.That(path.IsEmpty, Is.False, "[Foo].IsEmpty");
                Assert.That(path.Count, Is.EqualTo(1), "[Foo].Count");
                Assert.That(path.Name, Is.EqualTo("Foo"), "[Foo].Name");
                Assert.That(path.ToString(), Is.EqualTo("Foo"), "[Foo].ToString()");
                Assert.That(path[0].Name, Is.EqualTo("Foo"), "[Foo][0]");
                Assert.That(path[0].LayerId, Is.EqualTo(string.Empty), "[Foo][0]");
                Assert.That(path.GetParent(), Is.EqualTo(FdbPath.Empty), "[Foo].Name");

                Assert.That(path, Is.EqualTo(path), "[Foo].Equals([Foo])");
#pragma warning disable CS1718 // Comparison made to same variable
                // ReSharper disable EqualExpressionComparison
                Assert.That(path == path, Is.True, "[Foo] == [Foo]");
                Assert.That(path != path, Is.False, "[Foo] != [Foo]");
                // ReSharper restore EqualExpressionComparison
#pragma warning restore CS1718 // Comparison made to same variable

                Assert.That(path, Is.EqualTo(FdbPath.Relative("Foo")), "[Foo].Equals([Foo]')");
                Assert.That(path, Is.EqualTo(FdbPath.Relative("Foo", "Bar").GetParent()), "[Foo].Equals([Foo/Bar].GetParent())");

                Assert.That(path, Is.Not.EqualTo(FdbPath.Empty), "[Foo].Equals(Empty)");
                Assert.That(path == FdbPath.Empty, Is.False, "[Foo] == Empty");
                Assert.That(path != FdbPath.Empty, Is.True, "[Foo] != Empty");
            }

            {
                var path1 = FdbPath.Relative("Foo", "Bar");
                var path2 = FdbPath.Parse("Foo/Bar");
                var path3 = new FdbPath(new[] { FdbPathSegment.Create("Foo"), FdbPathSegment.Create("Bar") }, false);

                Assert.That(path2, Is.EqualTo(path1), "path1 eq path2");
                Assert.That(path3, Is.EqualTo(path1), "path1 eq path3");
                Assert.That(path3, Is.EqualTo(path2), "path2 eq path3");

                Assert.That(path2.GetHashCode(), Is.EqualTo(path1.GetHashCode()), "h(path1) == h(path2)");
                Assert.That(path3.GetHashCode(), Is.EqualTo(path1.GetHashCode()), "h(path1) == h(path3)");
            }
        }
        public void Test_FdbPath_Root()
        {
            var root = FdbPath.Root;

            Assert.That(root.IsAbsolute, Is.True);
            Assert.That(root.IsEmpty, Is.False);
            Assert.That(root.IsRoot, Is.True);
            Assert.That(root.Count, Is.EqualTo(0));
            Assert.That(root.ToString(), Is.EqualTo("/"));
            Assert.That(root.Name, Is.EqualTo(string.Empty));
            Assert.That(root.Segments.Length, Is.EqualTo(0));
            Assert.That(root.ToArray(), Is.EqualTo(new string[0]));

            Assert.That(root, Is.EqualTo(FdbPath.Root));
            Assert.That(root == FdbPath.Root, Is.True);
            Assert.That(root != FdbPath.Root, Is.False);
            Assert.That(root, Is.Not.EqualTo(FdbPath.Empty));
            Assert.That(root == FdbPath.Empty, Is.False);
            Assert.That(root != FdbPath.Empty, Is.True);

            Assert.That(FdbPath.Parse("Hello").StartsWith(root), Is.False);
            Assert.That(FdbPath.Parse("/Hello").StartsWith(root), Is.True);
        }
        public void Test_FdbPath_Empty()
        {
            var empty = FdbPath.Empty;

            Assert.That(empty.IsAbsolute, Is.False);
            Assert.That(empty.IsEmpty, Is.True);
            Assert.That(empty.IsRoot, Is.False);
            Assert.That(empty.Count, Is.EqualTo(0));
            Assert.That(empty.ToString(), Is.EqualTo(string.Empty));
            Assert.That(empty.Name, Is.EqualTo(string.Empty));
            Assert.That(empty.Segments.Length, Is.EqualTo(0));
            Assert.That(empty.ToArray(), Is.EqualTo(new string[0]));

            Assert.That(empty, Is.EqualTo(FdbPath.Empty));
            Assert.That(empty == FdbPath.Empty, Is.True);
            Assert.That(empty != FdbPath.Empty, Is.False);
            Assert.That(empty, Is.Not.EqualTo(FdbPath.Root));
            Assert.That(empty == FdbPath.Root, Is.False);
            Assert.That(empty != FdbPath.Root, Is.True);

            Assert.That(FdbPath.Parse("Hello").StartsWith(empty), Is.True);
            Assert.That(FdbPath.Parse("/Hello").StartsWith(empty), Is.False);
        }
Exemple #6
0
 private static FdbDirectorySubspaceLocation ParsePath(string path)
 {
     return(Db.Root[FdbPath.Parse(path)]);
     //path = path.Replace("\\", "/").Trim();
     //return path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
 }
Exemple #7
0
        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();
            }
        }
Exemple #8
0
        static void Main(string[] args)
        {
            bool stop = false;

            string clusterFile = null;
            var    partition   = FdbPath.Root;

            int    pStart       = 0;
            string startCommand = null;

            while (pStart < args.Length)
            {
                if (args[pStart].StartsWith("-"))
                {
                    switch (args[pStart].Substring(1))
                    {
                    case "C":
                    case "c":
                    {
                        clusterFile = args[pStart + 1];
                        pStart     += 2;
                        break;
                    }

                    case "P":
                    case "p":
                    {
                        partition = FdbPath.Parse(args[pStart + 1].Trim());
                        pStart   += 2;
                        break;
                    }

                    default:
                    {
                        Console.WriteLine($"Unknown option : '{args[pStart]}'");
                        pStart++;
                        break;
                    }
                    }
                }
                else
                {
                    break;
                }
            }

            if (args.Length > 0 && pStart < args.Length)
            {             // the remainder of the command line will be the first command to execute
                startCommand = String.Join(" ", args, pStart, args.Length - pStart);
            }

            var go = new CancellationTokenSource();

            // Initialize FDB
            Fdb.Start(Fdb.GetDefaultApiVersion());
            try
            {
                var options = new FdbConnectionOptions
                {
                    ClusterFile = clusterFile,
                    Root        = partition,
                };
                Db = Fdb.OpenAsync(options, go.Token).GetAwaiter().GetResult();

                using (Db)
                {
                    Db.DefaultTimeout    = 30 * 1000;
                    Db.DefaultRetryLimit = 10;

                    Console.WriteLine("Using API v" + Fdb.ApiVersion + " (max " + Fdb.GetMaxApiVersion() + ")");
                    Console.WriteLine("Cluster file: " + (clusterFile ?? "<default>"));

                    Console.WriteLine();
                    Console.WriteLine("FoundationDB Samples menu:");
                    Console.WriteLine("\t1\tRun Class Scheduling sample");
                    Console.WriteLine("\tL\tRun Leak test");
                    Console.WriteLine("\tbench\tRun synthetic benchmarks");
                    Console.WriteLine("\tgc\tTrigger a .NET garbage collection");
                    Console.WriteLine("\tmem\tDisplay memory usage statistics");
                    Console.WriteLine("\tq\tQuit");

                    Console.WriteLine("Ready...");

                    while (!stop)
                    {
                        Console.Write("> ");
                        string s = startCommand != null ? startCommand : Console.ReadLine();
                        startCommand = null;

                        var    tokens = s.Trim().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        string cmd    = tokens.Length > 0 ? tokens[0] : String.Empty;
                        string prm    = tokens.Length > 1 ? tokens[1] : String.Empty;

                        var trimmedCommand = cmd.Trim().ToLowerInvariant();
                        switch (trimmedCommand)
                        {
                        case "":
                        {
                            continue;
                        }

                        case "1":
                        {                                 // Class Scheduling
                            RunAsyncTest(new ClassScheduling(), go.Token);
                            break;
                        }

                        case "log":
                        {
                            switch (prm.ToLowerInvariant())
                            {
                            case "on":
                            {
                                LogEnabled = true;
                                Console.WriteLine("# Logging enabled");
                                break;
                            }

                            case "off":
                            {
                                LogEnabled = false;
                                Console.WriteLine("# Logging disabled");
                                break;
                            }

                            default:
                            {
                                Console.WriteLine("# Logging is {0}", LogEnabled ? "ON" : "OFF");
                                break;
                            }
                            }
                            break;
                        }

                        case "bench":
                        {                                 // Benchs
                            switch (prm.ToLowerInvariant())
                            {
                            case "read":
                            {
                                RunAsyncTest(new BenchRunner(BenchRunner.BenchMode.GetReadVersion), go.Token);
                                break;
                            }

                            case "get":
                            {
                                RunAsyncTest(new BenchRunner(BenchRunner.BenchMode.Get), go.Token);
                                break;
                            }

                            case "get10":
                            {
                                RunAsyncTest(new BenchRunner(BenchRunner.BenchMode.Get, 10), go.Token);
                                break;
                            }

                            case "set":
                            {                                             // Bench Set
                                RunAsyncTest(new BenchRunner(BenchRunner.BenchMode.Set), go.Token);
                                break;
                            }

                            case "watch":
                            {                                             // Bench Set
                                RunAsyncTest(new BenchRunner(BenchRunner.BenchMode.Watch), go.Token);
                                break;
                            }
                            }

                            break;
                        }

                        case "msg":
                        {
                            switch (prm.ToLowerInvariant())
                            {
                            case "producer":
                            {                                             // Queue Producer
                                RunAsyncTest(new MessageQueueRunner(PerfCounters.ProcessName + "[" + PerfCounters.ProcessId + "]", MessageQueueRunner.AgentRole.Producer, TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(200)), go.Token);
                                break;
                            }

                            case "worker":
                            {                                             // Queue Worker
                                RunAsyncTest(new MessageQueueRunner(PerfCounters.ProcessName + "[" + PerfCounters.ProcessId + "]", MessageQueueRunner.AgentRole.Worker, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(10)), go.Token);
                                break;
                            }

                            case "clear":
                            {                                             // Queue Clear
                                RunAsyncTest(new MessageQueueRunner(PerfCounters.ProcessName + "[" + PerfCounters.ProcessId + "]", MessageQueueRunner.AgentRole.Clear, TimeSpan.Zero, TimeSpan.Zero), go.Token);
                                break;
                            }

                            case "status":
                            {                                             // Queue Status
                                RunAsyncTest(new MessageQueueRunner(PerfCounters.ProcessName + "[" + PerfCounters.ProcessId + "]", MessageQueueRunner.AgentRole.Status, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(10)), go.Token);
                                break;
                            }
                            }
                            break;
                        }

                        case "leak":
                        {                                 // LeastTest
                            switch (prm.ToLowerInvariant())
                            {
                            case "fast": RunAsyncTest(new LeakTest(100, 100, 1000, TimeSpan.FromSeconds(0)), go.Token); break;

                            case "slow": RunAsyncTest(new LeakTest(100, 100, 1000, TimeSpan.FromSeconds(30)), go.Token); break;

                            default: RunAsyncTest(new LeakTest(100, 100, 1000, TimeSpan.FromSeconds(1)), go.Token); break;
                            }
                            break;
                        }

                        case "sampling":
                        {                                 // SamplingTest
                            RunAsyncTest(new SamplerTest(0.1), go.Token);
                            break;
                        }

                        case "q":
                        case "x":
                        case "quit":
                        case "exit":
                        {
                            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("- Managed Mem  : " + GC.GetTotalMemory(false).ToString("N0"));
#if !NETCOREAPP
                            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("- BytesInAlHeap: " + PerfCounters.ClrBytesInAllHeaps.NextValue().ToString("N0"));
#endif
                            break;
                        }

                        default:
                        {
                            Console.WriteLine(string.Format("Unknown command : '{0}'", trimmedCommand));
                            break;
                        }
                        }
                    }
                }
            }
            finally
            {
                go.Cancel();
                Fdb.Stop();
                Console.WriteLine("Bye");
            }
        }
        private static async Task MainAsync(CancellationToken ct)
        {
            // change the path to the native lib if not default
            if (NATIVE_PATH != null)
            {
                Fdb.Options.SetNativeLibPath(NATIVE_PATH);
            }

            // uncomment this to enable network thread tracing
            // FdbCore.TracePath = Path.Combine(Path.GetTempPath(), "fdb");

            int apiVersion = Fdb.GetMaxApiVersion();

            Console.WriteLine("Max API Version: " + apiVersion);

            try
            {
                Console.WriteLine("Starting network thread...");
                Fdb.Start(Fdb.GetDefaultApiVersion());
                Console.WriteLine("> Up and running");

                var settings = new FdbConnectionOptions()
                {
                    ClusterFile = CLUSTER_FILE,
                    Root        = FdbPath.Parse("/Sandbox"),
                };

                Console.WriteLine("Connecting to local cluster...");
                using (var db = await Fdb.OpenAsync(settings, ct))
                {
                    Console.WriteLine("> Connected!");

                    // get coordinators
                    var cf = await Fdb.System.GetCoordinatorsAsync(db, ct);

                    Console.WriteLine("Coordinators: " + cf.ToString());

                    // clear everything
                    using (var tr = await db.BeginTransactionAsync(ct))
                    {
                        Console.WriteLine("Clearing subspace " + db.Root + " ...");
                        var subspace = await db.Root.Resolve(tr);

                        tr.ClearRange(subspace);
                        await tr.CommitAsync();

                        Console.WriteLine("> Database cleared");
                    }

                    Console.WriteLine();

                    await TestSimpleTransactionAsync(db, ct);

                    await BenchInsertSmallKeysAsync(db, N, 16, ct);                     // some guid
                    await BenchInsertSmallKeysAsync(db, N, 60 * 4, ct);                 // one Int32 per minutes, over an hour
                    await BenchInsertSmallKeysAsync(db, N, 512, ct);                    // small JSON payload
                    await BenchInsertSmallKeysAsync(db, N / 5, 4096, ct);               // typical small cunk size
                    await BenchInsertSmallKeysAsync(db, N / 100, 65536, ct);            // typical medium chunk size
                    await BenchInsertSmallKeysAsync(db, 20, 100_000, ct);               // Maximum value size (as of beta 1)

                    // insert keys in parrallel
                    await BenchConcurrentInsert(db, 1, 100, 512, ct);
                    await BenchConcurrentInsert(db, 1, 1_000, 512, ct);
                    await BenchConcurrentInsert(db, 1, 10_000, 512, ct);

                    await BenchConcurrentInsert(db, 1, N, 16, ct);
                    await BenchConcurrentInsert(db, 2, N, 16, ct);
                    await BenchConcurrentInsert(db, 4, N, 16, ct);
                    await BenchConcurrentInsert(db, 8, N, 16, ct);
                    await BenchConcurrentInsert(db, 16, N, 16, ct);

                    await BenchSerialWriteAsync(db, N, ct);
                    await BenchSerialReadAsync(db, N, ct);
                    await BenchConcurrentReadAsync(db, N, ct);

                    await BenchClearAsync(db, N, ct);

                    await BenchUpdateSameKeyLotsOfTimesAsync(db, 1000, ct);

                    await BenchUpdateLotsOfKeysAsync(db, 1000, ct);

                    await BenchBulkInsertThenBulkReadAsync(db, 100_000, 50, 128, ct);
                    await BenchBulkInsertThenBulkReadAsync(db, 100_000, 128, 50, ct);
                    await BenchBulkInsertThenBulkReadAsync(db, 1_000_000, 50, 128, ct);

                    await BenchMergeSortAsync(db, 100, 3, 20, ct);
                    await BenchMergeSortAsync(db, 1_000, 10, 100, ct);
                    await BenchMergeSortAsync(db, 100, 100, 100, ct);
                    await BenchMergeSortAsync(db, 100, 1_000, 100, ct);

                    Console.WriteLine("time to say goodbye...");
                }
            }
            finally
            {
                Console.WriteLine("### DONE ###");
                Fdb.Stop();
            }
#if DEBUG
            Console.ReadLine();
#endif
        }
        public void Test_FdbPath_Parse()
        {
            // Relative paths

            FdbPath Parse(string value)
            {
                Log($"\"{value}\":");
                var path = FdbPath.Parse(value);

                if (path.IsEmpty)
                {
                    Log("> <empty>");
                }
                else if (path.IsRoot)
                {
                    Log("> <root>");
                }
                else
                {
                    Log($"> Path='{path.ToString()}', Count={path.Count}, Name='{path.Name}', Absolute={path.IsAbsolute}");
                }
                return(path);
            }

            {             // Empty
                var path = Parse("");
                Assert.That(path.IsAbsolute, Is.False, ".Absolute");
                Assert.That(path.IsRoot, Is.False, ".IsRoot");
                Assert.That(path.IsEmpty, Is.True, ".IsEmpty");
                Assert.That(path.Count, Is.EqualTo(0), ".Count");
                Assert.That(path.ToString(), Is.EqualTo(""));
                Assert.That(path.Name, Is.EqualTo(string.Empty));
            }
            {             // Foo
                var path = Parse("Foo");
                Assert.That(path.IsAbsolute, Is.False, ".Absolute");
                Assert.That(path.IsRoot, Is.False, ".IsRoot");
                Assert.That(path.IsEmpty, Is.False, ".IsEmpty");
                Assert.That(path.Count, Is.EqualTo(1), ".Count");
                Assert.That(path[0].Name, Is.EqualTo("Foo"));
                Assert.That(path[0].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path.ToString(), Is.EqualTo("Foo"));
                Assert.That(path.Name, Is.EqualTo("Foo"));
            }
            {             // Foo/Bar/Baz
                var path = Parse("Foo/Bar/Baz");
                Assert.That(path.IsAbsolute, Is.False, ".Absolute");
                Assert.That(path.IsRoot, Is.False, ".IsRoot");
                Assert.That(path.IsEmpty, Is.False, ".IsEmpty");
                Assert.That(path.Count, Is.EqualTo(3), ".Count");
                Assert.That(path[0].Name, Is.EqualTo("Foo"));
                Assert.That(path[0].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path[1].Name, Is.EqualTo("Bar"));
                Assert.That(path[1].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path[2].Name, Is.EqualTo("Baz"));
                Assert.That(path[2].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path.ToString(), Is.EqualTo("Foo/Bar/Baz"));
                Assert.That(path.Name, Is.EqualTo("Baz"));
            }

            // Absolute path

            {             // Root ("/")
                var path = Parse("/");
                Assert.That(path.IsAbsolute, Is.True, ".Absolute");
                Assert.That(path.IsEmpty, Is.False, ".IsEmpty");
                Assert.That(path.IsRoot, Is.True, ".IsRoot");
                Assert.That(path.Count, Is.EqualTo(0));
                Assert.That(path.ToString(), Is.EqualTo("/"));
                Assert.That(path.Name, Is.EqualTo(string.Empty));
            }
            {             // /Foo
                var path = Parse("/Foo");
                Assert.That(path.IsAbsolute, Is.True, ".Absolute");
                Assert.That(path.IsEmpty, Is.False, ".IsEmpty");
                Assert.That(path.IsRoot, Is.False, ".IsRoot");
                Assert.That(path.Count, Is.EqualTo(1));
                Assert.That(path[0].Name, Is.EqualTo("Foo"));
                Assert.That(path[0].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path.ToString(), Is.EqualTo("/Foo"));
                Assert.That(path.Name, Is.EqualTo("Foo"));
            }

            {             // /Foo/Bar/Baz
                var path = Parse("/Foo/Bar/Baz");
                Assert.That(path.IsAbsolute, Is.True, ".Absolute");
                Assert.That(path.IsEmpty, Is.False, ".IsEmpty");
                Assert.That(path.IsRoot, Is.False, ".IsRoot");
                Assert.That(path.Count, Is.EqualTo(3));
                Assert.That(path[0].Name, Is.EqualTo("Foo"));
                Assert.That(path[0].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path[1].Name, Is.EqualTo("Bar"));
                Assert.That(path[1].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path[2].Name, Is.EqualTo("Baz"));
                Assert.That(path[2].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path.ToString(), Is.EqualTo("/Foo/Bar/Baz"));
                Assert.That(path.Name, Is.EqualTo("Baz"));
            }
            {             // /Foo\/Bar/Baz => { "Foo/Bar", "Baz" }
                var path = Parse(@"/Foo\/Bar/Baz");
                Assert.That(path.IsAbsolute, Is.True, ".Absolute");
                Assert.That(path.IsEmpty, Is.False, ".IsEmpty");
                Assert.That(path.IsRoot, Is.False, ".IsRoot");
                Assert.That(path.Count, Is.EqualTo(2));
                Assert.That(path[0].Name, Is.EqualTo("Foo/Bar"));
                Assert.That(path[0].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path[1].Name, Is.EqualTo("Baz"));
                Assert.That(path[1].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path.ToString(), Is.EqualTo(@"/Foo\/Bar/Baz"));
                Assert.That(path.Name, Is.EqualTo("Baz"));
            }
            {             // /Foo\\Bar/Baz => { @"Foo\Bar", "Baz" }
                var path = Parse(@"/Foo\\Bar/Baz");
                Assert.That(path.IsAbsolute, Is.True, ".Absolute");
                Assert.That(path.IsEmpty, Is.False, ".IsEmpty");
                Assert.That(path.IsRoot, Is.False, ".IsRoot");
                Assert.That(path.Count, Is.EqualTo(2));
                Assert.That(path[0].Name, Is.EqualTo("Foo\\Bar"));
                Assert.That(path[0].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path[1].Name, Is.EqualTo("Baz"));
                Assert.That(path[1].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path.ToString(), Is.EqualTo(@"/Foo\\Bar/Baz"));
                Assert.That(path.Name, Is.EqualTo("Baz"));
            }
            {             // /Foo[Bar]/Baz => { "Foo[Bar]", "Baz" }
                var path = Parse("/Foo\\[Bar]/Baz");
                Assert.That(path.IsAbsolute, Is.True, ".Absolute");
                Assert.That(path.IsEmpty, Is.False, ".IsEmpty");
                Assert.That(path.IsRoot, Is.False, ".IsRoot");
                Assert.That(path.Count, Is.EqualTo(2));
                Assert.That(path[0].Name, Is.EqualTo("Foo[Bar]"));
                Assert.That(path[0].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path[1].Name, Is.EqualTo("Baz"));
                Assert.That(path[1].LayerId, Is.EqualTo(string.Empty));
                Assert.That(path.ToString(), Is.EqualTo(@"/Foo\[Bar\]/Baz"));
                Assert.That(path.Name, Is.EqualTo("Baz"));
            }

            // Layers

            {             // "/Foo[Test]"
                var path = Parse("/Foo[test]");
                Assert.That(path.IsAbsolute, Is.True);
                Assert.That(path.ToString(), Is.EqualTo("/Foo[test]"));
                Assert.That(path.IsEmpty, Is.False);
                Assert.That(path.IsRoot, Is.False);
                Assert.That(path.Count, Is.EqualTo(1));
                Assert.That(path[0].Name, Is.EqualTo("Foo"));
                Assert.That(path[0].LayerId, Is.EqualTo("test"));
                Assert.That(path.Name, Is.EqualTo("Foo"));
                Assert.That(path.LayerId, Is.EqualTo("test"));
                Assert.That(path.ToArray(), Is.EqualTo(new [] { FdbPathSegment.Create("Foo", "test") }));
                Assert.That(path.StartsWith(FdbPath.Root), Is.True);
                Assert.That(path.IsChildOf(FdbPath.Root), Is.True);
                Assert.That(path.EndsWith(FdbPath.Root), Is.False);
                Assert.That(path.IsParentOf(FdbPath.Root), Is.False);
            }

            // invalid paths
            {
                // "/Foo//Baz" => empty segment
                Assert.That(() => FdbPath.Parse("/Foo//Baz"), Throws.InstanceOf <FormatException>());

                // "/Foo/Bar/" => last is empty
                Assert.That(() => FdbPath.Parse("/Foo/Bar/"), Throws.InstanceOf <FormatException>());
            }
        }