CrustyDB is an academic Rust-based relational database management system
Make sure you have Rust > 1.57.0. Updating the rust toolkit is pretty easy, just do:
$ rustup update
You can then check the version by doing:
$ rustc --version
By default the cargo/rust version on cs.linux or vdesk is out of date. However, techstaff has set up a way for you to use 1.65+. You must run the following command on login.
$ module load rust
You can verify this worked with
$ rustc --version
rustc 1.65.0
$ cargo --version
cargo 1.65.0
Most crates have tests that can be run using cargo cargo test
. Like building you can run tests for a single crate cargo test -p common
. Note that tests will build/compile code in the tests modules, so you may encounter build errors here that do not show up in a regular build.
Some longer tests are set to be ignored by default. To run them: cargo test -- --ignored
CrustyDB uses the env_logger crate for logging. Per the docs on the log crate:
The basic use of the log crate is through the five logging macros: error!, warn!, info!, debug! and trace!
where error! represents the highest-priority log messages and trace! the lowest.
The log messages are filtered by configuring the log level to exclude messages with a lower priority.
Each of these macros accept format strings similarly to println!.
The logging level is set by an environmental variable, RUST_LOG
. The easiest way to set the level is when running a cargo command you set the logging level in the same command. EG : RUST_LOG=debug cargo run --bin server
. However, when running unit tests the logging/output is suppressed and the logger is not initialized. So if you want to use logging for a test you must:
- Make sure the test in question calls
init()
which is defined incommon::testutils
that initializes the logger. It can safely be called multiple times. - Tell cargo to not capture the output. For example, setting the level to DEBUG:
RUST_LOG=debug cargo test -- --nocapture [opt_test_name]
note the -- before --nocapture
Examples:
RUST_LOG=debug cargo run --bin server
RUST_LOG=debug cargo test
RUST_LOG=debug cargo test -- --nocapture [test_name]
In addition, the log level can also be controlled programmatically. The log level is set in the first line of the main() function in the server crate. By default, this is set to DEBUG. Feel free to change this as you see fit.
This is the basic process for starting a database and connecting to it via the CLI client.
-
Start a server thread
$ cargo run --bin server
-
Start a client
$ cargo run --bin cli-crusty
For convenience we have provided some shell scripts to run the server and client. The server has a debug and info mode for the logger.
CrustyDB emulates psql commands.
Command | Functionality |
---|---|
\r [DATABABSE] |
cReates a new database, DATABASE |
\c [DATABASE] |
Connects to DATABASE |
\i [PATH] [TABLE_NAME] |
Imports a csv file at PATH and saves it to TABLE_NAME in |
whatever database the client is currently connected to. | |
\l |
List the name of all databases present on the server. |
\dt |
List the name of all tables present on the current database. |
\generate [CSV_NAME] [NUMBER_OF_RECORDS] |
Generate a test CSV for a sample schema. |
\reset |
Calls the reset command. This should delete all data and state for all databases on the server |
\close |
Closes the current client, but leaves the database server running |
\shutdown |
Shuts down the database server cleanly (allows the DB to gracefully exit) |
There are other commands you can ignore for this class (register, runFull, runPartial, convert).
The client also handles basic SQL queries.
After compiling the database, start a server and a client instance.
To start the crustydb server:
$ cargo run --bin server
and to start the client:
$ cargo run --bin cli-crusty
Now, from the client, you can interact with the server. Create a database named 'testdb':
[crustydb]>> \r testdb
Then, connect to the newly created database:
[crustydb]>> \c testdb
At this point, you can create a table 'test' in the 'testdb' database you are connected to by writing the appropriate SQL command. Let's create a table with 2 Integer columns, which we are going to name 'a' and 'b'.
[crustydb]>> CREATE TABLE test (a INT, b INT, primary key (a));
At this point the table exists in the database, but it does not contain any data. We include a CSV file in the repository (named 'data.csv') with some sample data you can import into the newly created table. You can do that by doing:
[crustydb]>> \i <PATH>/data.csv test
Note that you need to replace PATH with the path to the repository where the data.csv file lives.
After importing the data, you can run basic SQL queries on the table. For example:
[crustydb]>> SELECT a FROM test;
or:
[crustydb]>> SELECT sum(a), sum(b) FROM test;
As you follow through this end to end example, we encourage you to take a look at the log messages emitted by the server. You can search for those log messages in the code: that is a great way of understanding the lifecycle of query execution in crustydb.
The client has an option of running a series of commands/queries from a text file.
Each command or query must be separated by a ; (even commands that would not give
a ; after when using the cli tool). To use the script pass -- -s [script file]
We have included a sample script that you would invoke the following way:
cargo run -p cli-crusty -- -s test-client-script
Debugging is a crucial skill you should learn (if you don't know yet) in order to become a more effective software developer. If you write software, your software will contain bugs. Debugging is the process of finding those bugs, which is necessary if you want to fix them.
There are tools to help you debug software called debuggers. You may have already heard about these. For example, in the C, C++ world, gdb and lldb are two popular debuggers. gdb is used to debug programs that have been compiled with gcc, while lldb is used to debug programs compiled with the LLVM toolkit. What this means in practice, in 2020, is that if you work on a Linux platform, you'll likely be using gdb. If you work on a Mac OS platform, you'll likely be using lldb. If you work on a windows platform, then you may be using either one, depending on your configuration.
A popular way of writing software is via IDEs (which we recommend you use to develop crustyDB). IDEs for most languages come with a debugger preconfigured. The situation for Rust is a little different. Only relatively recently IDE developers have started incorporating debuggers for Rust, and the support is still sparse. If you use Visual Studio Code (a lightweight and open source IDE), you will be able to use a Rust debugger (based on gdb or lldb depending on the underlying platform). You can easily find instructions online on how to set this up.
Most other free IDEs do not have good support for the Rust debugger yet.
JetBrain's CLion IDE looks to have a solid Rust debugger with the Rust extension. However CLion is not free, but it does offer academic licenses. Apply here if you want to access the tool (some restrictions on what you can use the tool for). Here are instructions on set up and using which worked for me out of the box on Ubuntu (with installing the Rust plugin). One of our TAs uses CLion to debug Rust on OSX. The link also contains instructions for debugging on Windows, but it has not been tested by us.
We have had some mixed success with using VSCode for debugging Rust (although it is a great Rust IDE with the right extensions). Using the extensions Rust and CodeLLDB on Ubuntu has gotten debugging working on a set up. We included the launch.json for running tests in a package.
You are already familiar with printing the values of variables in your programs in order to understand program behavior and detect problems, i.e., in order to debug your programs. Rust has its own println!() macro (and Crusty uses a logging library). Rust also has a dbg!() macro in its standard library, which will simply format the argument so its printable along with the line where it's found. A real debugger will give you much more information, presented better, and in context, so it's a much more powerful way of debugging programs, and the recommended way. However, in some instances, the macros above may come in handy, especially as Rust's debuggers support matures.