-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
DOCS(database): Add some crude high-level docs for DB #6928
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Krzmbrzl
wants to merge
1
commit into
mumble-voip:master
Choose a base branch
from
Krzmbrzl:docs-change-database
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # Server database | ||
|
|
||
| The Mumble server uses a database to persist data across restarts. This document is about the (high-level) implementation details. | ||
|
|
||
| The database implementation consists of two separate parts. First, the general DB wrappers that allow managing the database convenient from within C++ | ||
| (mostly) without having to worry about the exact backend that is used. Second, the server-specific implementation which encodes the exact identity of | ||
| tables and ways to access them. The former implementation lives under `src/database` and is completely decoupled from the server and even mostly | ||
| decoupled from Mumble as a whole. The latter lives under `src/murmur/database`. | ||
|
|
||
| Overall, we are using [SOCI](https://github.com/SOCI/soci/) for abstracting and unifying the low-level communication with different database backends. | ||
|
|
||
|
|
||
| ## Transactions | ||
|
|
||
| A core design philosophy of our database implementation is that **every** database operation (READ _and_ WRITE) is encapsulated by a transaction | ||
| ensuring that all operations happen atomically (from a logical point of view). | ||
|
|
||
| Oftentimes, a given function doesn't know whether the parent function has already created a transaction. To avoid creating deeply nested transactions, | ||
| the `Database` and `Table` base classes have a member function `ensureTransaction` that will create a transaction, if none is already in progress. The | ||
| returned `TransactionHolder` object can be treated the same in both cases as it has the necessary logic embedded to deal with cases in which no new | ||
| transaction was created. | ||
|
|
||
|
|
||
| ## Exceptions | ||
|
|
||
| Errors during any database operation are communicated by means of exceptions. In order to ensure that the exceptions will have the expected type, make | ||
| sure to always wrap SOCI operations in a `try`-`catch` block that rethrows exceptions wrapped in one of Mumble's own database exception classes. Use | ||
| `std::throw_with_nested` function of the C++ standard. | ||
|
|
||
|
|
||
| ## Database migrations | ||
|
|
||
| If a server is started on a database that has an older scheme version than the server wants to use, an automatic migration procedure is started that | ||
| will update the database to conform to the new scheme. This encompasses a complete re-creation of all tables followed by data migration from the old | ||
| tables into the new ones. Once everything has successfully completed, the old tables will be dropped. | ||
|
|
||
|
|
||
| ## Changing the database scheme | ||
|
|
||
| The database scheme is a monotonically increasing number that acts as a version number for the database layout. The layout encompasses the existence | ||
| of specific tables, columns (along with their data types) within tables and constraints, keys, etc. within tables. | ||
|
|
||
| Any changes to the database layout needs to be accompanied by the following steps: | ||
|
|
||
| 1. Increase the scheme version by one. The scheme version is defined by the constant `ServerDatabase::DB_SCHEME_VERSION` (see | ||
| [here](https://github.com/mumble-voip/mumble/blob/4ac51e86ff7b2243774d86a4d9fdac548127389a/src/murmur/database/ServerDatabase.h#L40). | ||
| 2. Adapt the `migrate` function of affected tables to data from the old table (which has the same name but with an added suffix of | ||
| `Database::OLD_TABLE_SUFFIX`) into the new table. If all data is simply copied from a column in the old table into a column of the same name in the | ||
| new table, without any required type transformations, it is sufficient to call the base implementation `Table::migrate` which will take care of | ||
| that. When implementing these function explicitly, it is important that while columns names in the new table should use the constants defined in | ||
| the `column` namespace, the names of the columns in the old table should always be written out **explicitly**. This is to ensure that even if the | ||
| names change in newer versions of the table (i.e. the ones in the `column` namespace change), the migration code still works as expected. For an | ||
| example see [here](https://github.com/mumble-voip/mumble/blob/4ac51e86ff7b2243774d86a4d9fdac548127389a/src/murmur/database/BanTable.cpp#L372). | ||
| 3. Add test cases for the migration path as well as the new DB functionality you added. | ||
|
|
||
|
|
||
| ### Migration test cases | ||
|
|
||
| Test cases for server migration are steered by the data found in `src/tests/TestDatabase/server/table_data`. This directory contains JSON files | ||
| describing the tables and their contents at different scheme versions along with the expected outcome after a successful migration has been performed | ||
| on that data. | ||
|
|
||
| By looking through the existing data, you should be able to get a feeling for the format. It should be noted that it is possible to inherit data from | ||
| previous scheme versions and then only perform modifications based off that. Again, search the existing examples for how to achieve this. Worst case, | ||
| you can also inspect `src/tests/TestDatabase/server/JSONAssembler.cpp` which is responsible for assembling the final JSON used to initialize the test | ||
| tables. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe instead of perma-linking to a specific version of that file and line, just link to the file on master instead without line? Could otherwise be confusing in the medium distant future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I wondered that as well but with the perma-link, I can at least be sure that the user sees what I want them to see even if the respective code has been moved somewhere else by the time the user is clicking on the link. In case of non-permanent links, that scenario could lead the user to a file that doesn't do what they came to witness 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well I think in that case the docs should be update, but it's just a small issue anyway. So feel free to ignore