mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sharp/fix-migration-issues' into 'master'
Fix various migration issues. See merge request veloren/veloren!1268
This commit is contained in:
commit
3a80b63e6a
@ -0,0 +1 @@
|
|||||||
|
-- This file should undo anything in `up.sql`
|
@ -0,0 +1,17 @@
|
|||||||
|
-- Delete invalid data caused by inconsistent enforcement of foreign key constraints.
|
||||||
|
DELETE FROM stats
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM character WHERE character.id = stats.character_id);
|
||||||
|
|
||||||
|
DELETE FROM body
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM character WHERE character.id = body.character_id);
|
||||||
|
|
||||||
|
DELETE FROM inventory
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM character WHERE character.id = inventory.character_id);
|
||||||
|
|
||||||
|
DELETE FROM loadout
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM character WHERE character.id = loadout.character_id);
|
||||||
|
|
||||||
|
-- Fix up incorrect skill data.
|
||||||
|
UPDATE stats
|
||||||
|
SET skills = json('{"skill_groups":[],"skills":[]}')
|
||||||
|
WHERE skills = json('""');
|
@ -234,7 +234,7 @@ impl Drop for CharacterLoader {
|
|||||||
/// After first logging in, and after a character is selected, we fetch this
|
/// After first logging in, and after a character is selected, we fetch this
|
||||||
/// data for the purpose of inserting their persisted data for the entity.
|
/// data for the purpose of inserting their persisted data for the entity.
|
||||||
fn load_character_data(player_uuid: &str, character_id: i32, db_dir: &str) -> CharacterDataResult {
|
fn load_character_data(player_uuid: &str, character_id: i32, db_dir: &str) -> CharacterDataResult {
|
||||||
let connection = establish_connection(db_dir);
|
let connection = establish_connection(db_dir)?;
|
||||||
|
|
||||||
let result = schema::character::dsl::character
|
let result = schema::character::dsl::character
|
||||||
.filter(schema::character::id.eq(character_id))
|
.filter(schema::character::id.eq(character_id))
|
||||||
@ -281,7 +281,7 @@ fn load_character_list(player_uuid: &str, db_dir: &str) -> CharacterListResult {
|
|||||||
.inner_join(schema::body::table)
|
.inner_join(schema::body::table)
|
||||||
.inner_join(schema::stats::table)
|
.inner_join(schema::stats::table)
|
||||||
.inner_join(schema::loadout::table)
|
.inner_join(schema::loadout::table)
|
||||||
.load::<(Character, Body, Stats, Loadout)>(&establish_connection(db_dir));
|
.load::<(Character, Body, Stats, Loadout)>(&establish_connection(db_dir)?);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(data) => Ok(data
|
Ok(data) => Ok(data
|
||||||
@ -322,7 +322,7 @@ fn create_character(
|
|||||||
) -> CharacterListResult {
|
) -> CharacterListResult {
|
||||||
check_character_limit(uuid, db_dir)?;
|
check_character_limit(uuid, db_dir)?;
|
||||||
|
|
||||||
let connection = establish_connection(db_dir);
|
let connection = establish_connection(db_dir)?;
|
||||||
|
|
||||||
connection.transaction::<_, diesel::result::Error, _>(|| {
|
connection.transaction::<_, diesel::result::Error, _>(|| {
|
||||||
use schema::{body, character, character::dsl::*, inventory, loadout, stats};
|
use schema::{body, character, character::dsl::*, inventory, loadout, stats};
|
||||||
@ -413,12 +413,20 @@ fn create_character(
|
|||||||
fn delete_character(uuid: &str, character_id: i32, db_dir: &str) -> CharacterListResult {
|
fn delete_character(uuid: &str, character_id: i32, db_dir: &str) -> CharacterListResult {
|
||||||
use schema::character::dsl::*;
|
use schema::character::dsl::*;
|
||||||
|
|
||||||
|
let connection = establish_connection(db_dir)?;
|
||||||
|
|
||||||
|
if let Err(e) = connection.transaction::<_, diesel::result::Error, _>(|| {
|
||||||
diesel::delete(
|
diesel::delete(
|
||||||
character
|
character
|
||||||
.filter(id.eq(character_id))
|
.filter(id.eq(character_id))
|
||||||
.filter(player_uuid.eq(uuid)),
|
.filter(player_uuid.eq(uuid)),
|
||||||
)
|
)
|
||||||
.execute(&establish_connection(db_dir))?;
|
.execute(&connection)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}) {
|
||||||
|
error!(?e, "Error during stats batch update transaction");
|
||||||
|
}
|
||||||
|
|
||||||
load_character_list(uuid, db_dir)
|
load_character_list(uuid, db_dir)
|
||||||
}
|
}
|
||||||
@ -432,7 +440,7 @@ fn check_character_limit(uuid: &str, db_dir: &str) -> Result<(), Error> {
|
|||||||
let character_count = character
|
let character_count = character
|
||||||
.select(count_star())
|
.select(count_star())
|
||||||
.filter(player_uuid.eq(uuid))
|
.filter(player_uuid.eq(uuid))
|
||||||
.load::<i64>(&establish_connection(db_dir))?;
|
.load::<i64>(&establish_connection(db_dir)?)?;
|
||||||
|
|
||||||
match character_count.first() {
|
match character_count.first() {
|
||||||
Some(count) => {
|
Some(count) => {
|
||||||
@ -511,7 +519,8 @@ impl CharacterUpdater {
|
|||||||
fn batch_update(updates: impl Iterator<Item = (i32, CharacterUpdateData)>, db_dir: &str) {
|
fn batch_update(updates: impl Iterator<Item = (i32, CharacterUpdateData)>, db_dir: &str) {
|
||||||
let connection = establish_connection(db_dir);
|
let connection = establish_connection(db_dir);
|
||||||
|
|
||||||
if let Err(e) = connection.transaction::<_, diesel::result::Error, _>(|| {
|
if let Err(e) = connection.and_then(|connection| {
|
||||||
|
connection.transaction::<_, diesel::result::Error, _>(|| {
|
||||||
updates.for_each(
|
updates.for_each(
|
||||||
|(character_id, (stats_update, inventory_update, loadout_update))| {
|
|(character_id, (stats_update, inventory_update, loadout_update))| {
|
||||||
update(
|
update(
|
||||||
@ -525,11 +534,13 @@ fn batch_update(updates: impl Iterator<Item = (i32, CharacterUpdateData)>, db_di
|
|||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}) {
|
}) {
|
||||||
error!(?e, "Error during stats batch update transaction");
|
error!(?e, "Error during stats batch update transaction");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// NOTE: Only call while a transaction is held!
|
||||||
fn update(
|
fn update(
|
||||||
character_id: i32,
|
character_id: i32,
|
||||||
stats: &StatsUpdate,
|
stats: &StatsUpdate,
|
||||||
|
@ -31,10 +31,16 @@ embed_migrations!();
|
|||||||
pub fn run_migrations(db_dir: &str) -> Result<(), diesel_migrations::RunMigrationsError> {
|
pub fn run_migrations(db_dir: &str) -> Result<(), diesel_migrations::RunMigrationsError> {
|
||||||
let db_dir = &apply_saves_dir_override(db_dir);
|
let db_dir = &apply_saves_dir_override(db_dir);
|
||||||
let _ = fs::create_dir(format!("{}/", db_dir));
|
let _ = fs::create_dir(format!("{}/", db_dir));
|
||||||
embedded_migrations::run_with_output(&establish_connection(db_dir), &mut std::io::stdout())
|
embedded_migrations::run_with_output(
|
||||||
|
&establish_connection(db_dir).expect(
|
||||||
|
"If we cannot execute migrations, we should not be allowed to launch the server, so \
|
||||||
|
we don't populate it with bad data.",
|
||||||
|
),
|
||||||
|
&mut std::io::stdout(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn establish_connection(db_dir: &str) -> SqliteConnection {
|
fn establish_connection(db_dir: &str) -> QueryResult<SqliteConnection> {
|
||||||
let db_dir = &apply_saves_dir_override(db_dir);
|
let db_dir = &apply_saves_dir_override(db_dir);
|
||||||
let database_url = format!("{}/db.sqlite", db_dir);
|
let database_url = format!("{}/db.sqlite", db_dir);
|
||||||
|
|
||||||
@ -45,18 +51,21 @@ fn establish_connection(db_dir: &str) -> SqliteConnection {
|
|||||||
// Set a busy timeout (in ms): https://sqlite.org/c3ref/busy_timeout.html
|
// Set a busy timeout (in ms): https://sqlite.org/c3ref/busy_timeout.html
|
||||||
if let Err(e) = connection.batch_execute(
|
if let Err(e) = connection.batch_execute(
|
||||||
"
|
"
|
||||||
|
PRAGMA foreign_keys = ON;
|
||||||
PRAGMA journal_mode = WAL;
|
PRAGMA journal_mode = WAL;
|
||||||
PRAGMA busy_timeout = 250;
|
PRAGMA busy_timeout = 250;
|
||||||
",
|
",
|
||||||
) {
|
) {
|
||||||
warn!(
|
warn!(
|
||||||
?e,
|
?e,
|
||||||
"Failed adding PRAGMA statements while establishing sqlite connection, this will \
|
"Failed adding PRAGMA statements while establishing sqlite connection, including \
|
||||||
result in a higher likelihood of locking errors"
|
enabling foreign key constraints. We will not allow connecting to the server under \
|
||||||
|
these conditions."
|
||||||
);
|
);
|
||||||
|
return Err(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
connection
|
Ok(connection)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_saves_dir_override(db_dir: &str) -> String {
|
fn apply_saves_dir_override(db_dir: &str) -> String {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user