forked from Qortal/qortal
Don't rebuild repository or export node-local data during repository build if repository was 'pristine'.
Under certain conditions, e.g. non-existent database files, the repository would be created and then immediately be re-created. Not only was this unnecessary, but HSQLDBDatabaseUpdates would attempt to export the node-local data twice, which would cause an error due to existing .script files. The fix is three-pronged: 1. Don't immediately rebuild the repository if it's only just been built 2. Don't export the empty node-local data if repository has only just been built 3. Don't export the node-local data if it's empty
This commit is contained in:
parent
806baa6ae4
commit
1f409235e4
@ -531,7 +531,8 @@ public class BlockChain {
|
|||||||
|
|
||||||
private static void rebuildBlockchain() throws DataException {
|
private static void rebuildBlockchain() throws DataException {
|
||||||
// (Re)build repository
|
// (Re)build repository
|
||||||
RepositoryManager.rebuild();
|
if (!RepositoryManager.wasPristineAtOpen())
|
||||||
|
RepositoryManager.rebuild();
|
||||||
|
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
GenesisBlock genesisBlock = GenesisBlock.getInstance(repository);
|
GenesisBlock genesisBlock = GenesisBlock.getInstance(repository);
|
||||||
|
@ -2,6 +2,8 @@ package org.qortal.repository;
|
|||||||
|
|
||||||
public interface RepositoryFactory {
|
public interface RepositoryFactory {
|
||||||
|
|
||||||
|
public boolean wasPristineAtOpen();
|
||||||
|
|
||||||
public RepositoryFactory reopen() throws DataException;
|
public RepositoryFactory reopen() throws DataException;
|
||||||
|
|
||||||
public Repository getRepository() throws DataException;
|
public Repository getRepository() throws DataException;
|
||||||
|
@ -8,6 +8,13 @@ public abstract class RepositoryManager {
|
|||||||
repositoryFactory = newRepositoryFactory;
|
repositoryFactory = newRepositoryFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean wasPristineAtOpen() throws DataException {
|
||||||
|
if (repositoryFactory == null)
|
||||||
|
throw new DataException("No repository available");
|
||||||
|
|
||||||
|
return repositoryFactory.wasPristineAtOpen();
|
||||||
|
}
|
||||||
|
|
||||||
public static Repository getRepository() throws DataException {
|
public static Repository getRepository() throws DataException {
|
||||||
if (repositoryFactory == null)
|
if (repositoryFactory == null)
|
||||||
throw new DataException("No repository available");
|
throw new DataException("No repository available");
|
||||||
|
@ -18,11 +18,16 @@ public class HSQLDBDatabaseUpdates {
|
|||||||
/**
|
/**
|
||||||
* Apply any incremental changes to database schema.
|
* Apply any incremental changes to database schema.
|
||||||
*
|
*
|
||||||
|
* @return true if database was non-existent/empty, false otherwise
|
||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
*/
|
*/
|
||||||
public static void updateDatabase(Connection connection) throws SQLException {
|
public static boolean updateDatabase(Connection connection) throws SQLException {
|
||||||
while (databaseUpdating(connection))
|
final boolean wasPristine = fetchDatabaseVersion(connection) == 0;
|
||||||
|
|
||||||
|
while (databaseUpdating(connection, wasPristine))
|
||||||
incrementDatabaseVersion(connection);
|
incrementDatabaseVersion(connection);
|
||||||
|
|
||||||
|
return wasPristine;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,23 +45,21 @@ public class HSQLDBDatabaseUpdates {
|
|||||||
/**
|
/**
|
||||||
* Fetch current version of database schema.
|
* Fetch current version of database schema.
|
||||||
*
|
*
|
||||||
* @return int, 0 if no schema yet
|
* @return database version, or 0 if no schema yet
|
||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
*/
|
*/
|
||||||
private static int fetchDatabaseVersion(Connection connection) throws SQLException {
|
private static int fetchDatabaseVersion(Connection connection) throws SQLException {
|
||||||
int databaseVersion = 0;
|
|
||||||
|
|
||||||
try (Statement stmt = connection.createStatement()) {
|
try (Statement stmt = connection.createStatement()) {
|
||||||
if (stmt.execute("SELECT version FROM DatabaseInfo"))
|
if (stmt.execute("SELECT version FROM DatabaseInfo"))
|
||||||
try (ResultSet resultSet = stmt.getResultSet()) {
|
try (ResultSet resultSet = stmt.getResultSet()) {
|
||||||
if (resultSet.next())
|
if (resultSet.next())
|
||||||
databaseVersion = resultSet.getInt(1);
|
return resultSet.getInt(1);
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
// empty database
|
// empty database
|
||||||
}
|
}
|
||||||
|
|
||||||
return databaseVersion;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,7 +68,7 @@ public class HSQLDBDatabaseUpdates {
|
|||||||
* @return true - if a schema update happened, false otherwise
|
* @return true - if a schema update happened, false otherwise
|
||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
*/
|
*/
|
||||||
private static boolean databaseUpdating(Connection connection) throws SQLException {
|
private static boolean databaseUpdating(Connection connection, boolean wasPristine) throws SQLException {
|
||||||
int databaseVersion = fetchDatabaseVersion(connection);
|
int databaseVersion = fetchDatabaseVersion(connection);
|
||||||
|
|
||||||
try (Statement stmt = connection.createStatement()) {
|
try (Statement stmt = connection.createStatement()) {
|
||||||
@ -695,11 +698,24 @@ public class HSQLDBDatabaseUpdates {
|
|||||||
case 30:
|
case 30:
|
||||||
// Split AT state data off to new table for better performance/management.
|
// Split AT state data off to new table for better performance/management.
|
||||||
|
|
||||||
if (!"mem".equals(HSQLDBRepository.getDbPathname(connection.getMetaData().getURL()))) {
|
if (!wasPristine && !"mem".equals(HSQLDBRepository.getDbPathname(connection.getMetaData().getURL()))) {
|
||||||
// First, backup node-local data in case user wants to avoid long reshape and use bootstrap instead
|
// First, backup node-local data in case user wants to avoid long reshape and use bootstrap instead
|
||||||
stmt.execute("PERFORM EXPORT SCRIPT FOR TABLE MintingAccounts DATA TO 'MintingAccounts.script'");
|
try (ResultSet resultSet = stmt.executeQuery("SELECT COUNT(*) FROM MintingAccounts")) {
|
||||||
stmt.execute("PERFORM EXPORT SCRIPT FOR TABLE TradeBotStates DATA TO 'TradeBotStates.script'");
|
int rowCount = resultSet.next() ? resultSet.getInt(1) : 0;
|
||||||
LOGGER.info("Exported sensitive/node-local data: minting keys and trade bot states");
|
if (rowCount > 0) {
|
||||||
|
stmt.execute("PERFORM EXPORT SCRIPT FOR TABLE MintingAccounts DATA TO 'MintingAccounts.script'");
|
||||||
|
LOGGER.info("Exported sensitive/node-local minting keys into MintingAccounts.script");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try (ResultSet resultSet = stmt.executeQuery("SELECT COUNT(*) FROM TradeBotStates")) {
|
||||||
|
int rowCount = resultSet.next() ? resultSet.getInt(1) : 0;
|
||||||
|
if (rowCount > 0) {
|
||||||
|
stmt.execute("PERFORM EXPORT SCRIPT FOR TABLE TradeBotStates DATA TO 'TradeBotStates.script'");
|
||||||
|
LOGGER.info("Exported sensitive/node-local trade-bot states into TradeBotStates.script");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LOGGER.info("If following reshape takes too long, use bootstrap and import node-local data using API's POST /admin/repository/data");
|
LOGGER.info("If following reshape takes too long, use bootstrap and import node-local data using API's POST /admin/repository/data");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ public class HSQLDBRepositoryFactory implements RepositoryFactory {
|
|||||||
|
|
||||||
private String connectionUrl;
|
private String connectionUrl;
|
||||||
private HSQLDBPool connectionPool;
|
private HSQLDBPool connectionPool;
|
||||||
|
private final boolean wasPristine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs new RepositoryFactory using passed <tt>connectionUrl</tt>.
|
* Constructs new RepositoryFactory using passed <tt>connectionUrl</tt>.
|
||||||
@ -65,12 +66,17 @@ public class HSQLDBRepositoryFactory implements RepositoryFactory {
|
|||||||
|
|
||||||
// Perform DB updates?
|
// Perform DB updates?
|
||||||
try (final Connection connection = this.connectionPool.getConnection()) {
|
try (final Connection connection = this.connectionPool.getConnection()) {
|
||||||
HSQLDBDatabaseUpdates.updateDatabase(connection);
|
this.wasPristine = HSQLDBDatabaseUpdates.updateDatabase(connection);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DataException("Repository initialization error", e);
|
throw new DataException("Repository initialization error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean wasPristineAtOpen() {
|
||||||
|
return this.wasPristine;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RepositoryFactory reopen() throws DataException {
|
public RepositoryFactory reopen() throws DataException {
|
||||||
return new HSQLDBRepositoryFactory(this.connectionUrl);
|
return new HSQLDBRepositoryFactory(this.connectionUrl);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user