Fixes for importing profiles while the server is running

- Have the active database return unloaded profiles during import (this triggers the giant warning messages)
 - Reload the users AFTER the conversion is complete, not BEFORE
This commit is contained in:
riking 2013-12-10 15:11:09 -08:00
parent 2aec4a69ea
commit 4f273ad6b4
5 changed files with 57 additions and 27 deletions

View File

@ -3,13 +3,10 @@ package com.gmail.nossr50.commands.database;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.database.DatabaseManager; import com.gmail.nossr50.database.DatabaseManager;
import com.gmail.nossr50.database.DatabaseManagerFactory; import com.gmail.nossr50.database.DatabaseManagerFactory;
import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.DatabaseType;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.runnables.database.DatabaseConversionTask; import com.gmail.nossr50.runnables.database.DatabaseConversionTask;
import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.player.UserManager;
@ -52,17 +49,6 @@ public class ConvertDatabaseCommand implements CommandExecutor {
sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Database.Start", previousType.toString(), newType.toString())); sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Database.Start", previousType.toString(), newType.toString()));
UserManager.saveAll(); UserManager.saveAll();
UserManager.clearAll();
for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
PlayerProfile profile = oldDatabase.loadPlayerProfile(player.getName(), false);
if (profile.isLoaded()) {
mcMMO.getDatabaseManager().saveUser(profile);
}
UserManager.addUser(player);
}
new DatabaseConversionTask(oldDatabase, sender, previousType.toString(), newType.toString()).runTaskAsynchronously(mcMMO.p); new DatabaseConversionTask(oldDatabase, sender, previousType.toString(), newType.toString()).runTaskAsynchronously(mcMMO.p);
return true; return true;

View File

@ -21,7 +21,8 @@ public interface DatabaseManager {
public void purgePowerlessUsers(); public void purgePowerlessUsers();
/** /**
* Purge users who haven't logged on in over a certain time frame from the database. * Purge users who haven't logged on in over a certain time frame from the
* database.
*/ */
public void purgeOldUsers(); public void purgeOldUsers();
@ -42,13 +43,13 @@ public interface DatabaseManager {
public boolean saveUser(PlayerProfile profile); public boolean saveUser(PlayerProfile profile);
/** /**
* Retrieve leaderboard info. * Retrieve leaderboard info.
* *
* @param skillName The skill to retrieve info on * @param skillName The skill to retrieve info on
* @param pageNumber Which page in the leaderboards to retrieve * @param pageNumber Which page in the leaderboards to retrieve
* @param statsPerPage The number of stats per page * @param statsPerPage The number of stats per page
* @return the requested leaderboard information * @return the requested leaderboard information
*/ */
public List<PlayerStat> readLeaderboard(SkillType skill, int pageNumber, int statsPerPage); public List<PlayerStat> readLeaderboard(SkillType skill, int pageNumber, int statsPerPage);
/** /**
@ -74,9 +75,9 @@ public interface DatabaseManager {
* *
* @param playerName The name of the player to load from the database * @param playerName The name of the player to load from the database
* @param createNew Whether to create a new record if the player is not * @param createNew Whether to create a new record if the player is not
* found * found
* @return The player's data, or an unloaded PlayerProfile if not found * @return The player's data, or an unloaded PlayerProfile if not found
* and createNew is false * and createNew is false
*/ */
public PlayerProfile loadPlayerProfile(String playerName, boolean createNew); public PlayerProfile loadPlayerProfile(String playerName, boolean createNew);
@ -96,9 +97,17 @@ public interface DatabaseManager {
public void convertUsers(DatabaseManager destination); public void convertUsers(DatabaseManager destination);
/** /**
* Retrieve the type of database in use. Custom databases should return CUSTOM. * Retrieve the type of database in use. Custom databases should return
* CUSTOM.
* *
* @return The type of database * @return The type of database
*/ */
public DatabaseType getDatabaseType(); public DatabaseType getDatabaseType();
/**
* Used for database conversion. If this is set to true, profiles may not
* be loaded from the database. This method will be called before and
* after database imports.
*/
public void setLoadingDisabled(boolean state);
} }

View File

@ -35,6 +35,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
private final long UPDATE_WAIT_TIME = 600000L; // 10 minutes private final long UPDATE_WAIT_TIME = 600000L; // 10 minutes
private final File usersFile; private final File usersFile;
private static final Object fileWritingLock = new Object(); private static final Object fileWritingLock = new Object();
private volatile boolean converting = false;
protected FlatfileDatabaseManager() { protected FlatfileDatabaseManager() {
usersFile = new File(mcMMO.getUsersFilePath()); usersFile = new File(mcMMO.getUsersFilePath());
@ -42,6 +43,10 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
updateLeaderboards(); updateLeaderboards();
} }
public void setLoadingDisabled(boolean state) {
converting = state;
}
public void purgePowerlessUsers() { public void purgePowerlessUsers() {
int purgedUsers = 0; int purgedUsers = 0;
@ -369,6 +374,10 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
} }
public PlayerProfile loadPlayerProfile(String playerName, boolean create) { public PlayerProfile loadPlayerProfile(String playerName, boolean create) {
if (converting) {
return new PlayerProfile(playerName, false);
}
BufferedReader in = null; BufferedReader in = null;
String usersFilePath = mcMMO.getUsersFilePath(); String usersFilePath = mcMMO.getUsersFilePath();

View File

@ -49,12 +49,19 @@ public final class SQLDatabaseManager implements DatabaseManager {
// How many connection attempts have failed // How many connection attempts have failed
private int reconnectAttempt = 0; private int reconnectAttempt = 0;
// If we're importing users, do not allow creation of profiles
private volatile boolean converting = false;
protected SQLDatabaseManager() { protected SQLDatabaseManager() {
checkStructure(); checkStructure();
new SQLDatabaseKeepaliveTask(this).runTaskTimerAsynchronously(mcMMO.p, 10, 60L * 60 * Misc.TICK_CONVERSION_FACTOR); new SQLDatabaseKeepaliveTask(this).runTaskTimerAsynchronously(mcMMO.p, 10, 60L * 60 * Misc.TICK_CONVERSION_FACTOR);
} }
public void setLoadingDisabled(boolean state) {
converting = state;
}
public void purgePowerlessUsers() { public void purgePowerlessUsers() {
if (!checkConnected()) { if (!checkConnected()) {
return; return;
@ -346,12 +353,16 @@ public final class SQLDatabaseManager implements DatabaseManager {
} }
public PlayerProfile loadPlayerProfile(String playerName, boolean create) { public PlayerProfile loadPlayerProfile(String playerName, boolean create) {
if (converting) {
return new PlayerProfile(playerName, false); // return unloaded profile during database conversion
}
return loadPlayerProfile(playerName, create, true); return loadPlayerProfile(playerName, create, true);
} }
private PlayerProfile loadPlayerProfile(String playerName, boolean create, boolean retry) { private PlayerProfile loadPlayerProfile(String playerName, boolean create, boolean retry) {
if (!checkConnected()) { if (!checkConnected()) {
return new PlayerProfile(playerName, false); // return fake profile if not connected return new PlayerProfile(playerName, false); // return unloaded profile if not connected
} }
PreparedStatement statement = null; PreparedStatement statement = null;

View File

@ -1,11 +1,14 @@
package com.gmail.nossr50.runnables.database; package com.gmail.nossr50.runnables.database;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.database.DatabaseManager; import com.gmail.nossr50.database.DatabaseManager;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.util.player.UserManager;
public class DatabaseConversionTask extends BukkitRunnable { public class DatabaseConversionTask extends BukkitRunnable {
private final DatabaseManager sourceDatabase; private final DatabaseManager sourceDatabase;
@ -20,12 +23,24 @@ public class DatabaseConversionTask extends BukkitRunnable {
@Override @Override
public void run() { public void run() {
sourceDatabase.convertUsers(mcMMO.getDatabaseManager()); try {
sourceDatabase.setLoadingDisabled(true);
sourceDatabase.convertUsers(mcMMO.getDatabaseManager());
}
finally {
sourceDatabase.setLoadingDisabled(false);
}
mcMMO.p.getServer().getScheduler().runTask(mcMMO.p, new Runnable() { mcMMO.p.getServer().getScheduler().runTask(mcMMO.p, new Runnable() {
@Override @Override
public void run() { public void run() {
sender.sendMessage(message); sender.sendMessage(message);
// Reload all users from the new database
UserManager.clearAll();
for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
UserManager.addUser(player);
}
} }
}); });
} }