Trial implementation of offline repository periodic maintenance.

Requires node shutdown, lots of time (10s of minutes), spare storage space.
Called via: java -cp qortal.jar org.qortal.RepositoryMaintenance
Not (yet) for general consumption.
This commit is contained in:
catbref 2020-08-31 11:51:38 +01:00
parent ce468d22dd
commit 3cc66609e8
3 changed files with 87 additions and 0 deletions

View File

@ -0,0 +1,75 @@
package org.qortal;
import java.security.Security;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
import org.qortal.controller.Controller;
import org.qortal.repository.DataException;
import org.qortal.repository.Repository;
import org.qortal.repository.RepositoryFactory;
import org.qortal.repository.RepositoryManager;
import org.qortal.repository.hsqldb.HSQLDBRepositoryFactory;
import org.qortal.settings.Settings;
public class RepositoryMaintenance {
static {
// This must go before any calls to LogManager/Logger
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
}
private static final Logger LOGGER = LogManager.getLogger(RepositoryMaintenance.class);
public static void main(String[] args) {
LOGGER.info("Repository maintenance starting up...");
Security.insertProviderAt(new BouncyCastleProvider(), 0);
Security.insertProviderAt(new BouncyCastleJsseProvider(), 1);
// Load/check settings, which potentially sets up blockchain config, etc.
try {
if (args.length > 0)
Settings.fileInstance(args[0]);
else
Settings.getInstance();
} catch (Throwable t) {
LOGGER.error("Settings file error: " + t.getMessage());
System.exit(2);
}
LOGGER.info("Opening repository");
try {
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(Controller.getRepositoryUrl());
RepositoryManager.setRepositoryFactory(repositoryFactory);
} catch (DataException e) {
// If exception has no cause then repository is in use by some other process.
if (e.getCause() == null) {
LOGGER.info("Repository in use by another process?");
} else {
LOGGER.error("Unable to start repository", e);
}
System.exit(1);
}
LOGGER.info("Starting repository periodic maintenance. This can take a while...");
try (final Repository repository = RepositoryManager.getRepository()) {
repository.performPeriodicMaintenance();
LOGGER.info("Repository periodic maintenance completed");
} catch (DataException e) {
LOGGER.error("Repository periodic maintenance failed", e);
}
try {
LOGGER.info("Shutting down repository");
RepositoryManager.closeRepositoryFactory();
} catch (DataException e) {
LOGGER.error("Error occurred while shutting down repository", e);
}
}
}

View File

@ -45,4 +45,6 @@ public interface Repository extends AutoCloseable {
public void backup(boolean quick) throws DataException;
public void performPeriodicMaintenance() throws DataException;
}

View File

@ -341,6 +341,16 @@ public class HSQLDBRepository implements Repository {
}
}
@Override
public void performPeriodicMaintenance() throws DataException {
// Defrag DB - takes a while!
try (Statement stmt = this.connection.createStatement()) {
stmt.execute("CHECKPOINT DEFRAG");
} catch (SQLException e) {
throw new DataException("Unable to defrag repository");
}
}
/** Returns DB pathname from passed connection URL. If memory DB, returns "mem". */
private static String getDbPathname(String connectionUrl) {
Pattern pattern = Pattern.compile("hsqldb:(mem|file):(.*?)(;|$)");