mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-03-25 10:32:00 +01:00
locking fixes for H2 updates
This commit is contained in:
@@ -29,10 +29,13 @@ import java.sql.SQLException;
|
|||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||||
|
import org.owasp.dependencycheck.exception.H2DBLockException;
|
||||||
import org.owasp.dependencycheck.utils.DBUtils;
|
import org.owasp.dependencycheck.utils.DBUtils;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||||
import org.owasp.dependencycheck.utils.FileUtils;
|
import org.owasp.dependencycheck.utils.FileUtils;
|
||||||
|
import org.owasp.dependencycheck.utils.H2DBLock;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -106,13 +109,20 @@ public final class ConnectionFactory {
|
|||||||
* @throws DatabaseException thrown if we are unable to connect to the
|
* @throws DatabaseException thrown if we are unable to connect to the
|
||||||
* database
|
* database
|
||||||
*/
|
*/
|
||||||
public void initialize() throws DatabaseException {
|
public synchronized void initialize() throws DatabaseException {
|
||||||
//this only needs to be called once.
|
//this only needs to be called once.
|
||||||
if (connectionString != null) {
|
if (connectionString != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
|
H2DBLock dblock = null;
|
||||||
try {
|
try {
|
||||||
|
if (isH2Connection()) {
|
||||||
|
dblock = new H2DBLock(settings);
|
||||||
|
LOGGER.debug("locking for init");
|
||||||
|
dblock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
//load the driver if necessary
|
//load the driver if necessary
|
||||||
final String driverName = settings.getString(Settings.KEYS.DB_DRIVER_NAME, "");
|
final String driverName = settings.getString(Settings.KEYS.DB_DRIVER_NAME, "");
|
||||||
if (!driverName.isEmpty()) {
|
if (!driverName.isEmpty()) {
|
||||||
@@ -174,7 +184,6 @@ public final class ConnectionFactory {
|
|||||||
throw new DatabaseException("Unable to connect to the database", ex);
|
throw new DatabaseException("Unable to connect to the database", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldCreateSchema) {
|
if (shouldCreateSchema) {
|
||||||
try {
|
try {
|
||||||
createTables(conn);
|
createTables(conn);
|
||||||
@@ -189,6 +198,8 @@ public final class ConnectionFactory {
|
|||||||
LOGGER.debug("", dex);
|
LOGGER.debug("", dex);
|
||||||
throw new DatabaseException("Database schema does not match this version of dependency-check", dex);
|
throw new DatabaseException("Database schema does not match this version of dependency-check", dex);
|
||||||
}
|
}
|
||||||
|
} catch (H2DBLockException ex) {
|
||||||
|
throw new DatabaseException("Unable to obtain an exclusive lock on the H2 database to perform initializataion", ex);
|
||||||
} finally {
|
} finally {
|
||||||
if (conn != null) {
|
if (conn != null) {
|
||||||
try {
|
try {
|
||||||
@@ -197,6 +208,9 @@ public final class ConnectionFactory {
|
|||||||
LOGGER.debug("An error occurred closing the connection", ex);
|
LOGGER.debug("An error occurred closing the connection", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (dblock != null) {
|
||||||
|
dblock.release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +220,7 @@ public final class ConnectionFactory {
|
|||||||
* finalize method being called as during shutdown the class loader used to
|
* finalize method being called as during shutdown the class loader used to
|
||||||
* load the driver may be unloaded prior to the driver being de-registered.
|
* load the driver may be unloaded prior to the driver being de-registered.
|
||||||
*/
|
*/
|
||||||
public void cleanup() {
|
public synchronized void cleanup() {
|
||||||
if (driver != null) {
|
if (driver != null) {
|
||||||
DriverLoader.cleanup(driver);
|
DriverLoader.cleanup(driver);
|
||||||
driver = null;
|
driver = null;
|
||||||
@@ -224,7 +238,7 @@ public final class ConnectionFactory {
|
|||||||
* @throws DatabaseException thrown if there is an exception loading the
|
* @throws DatabaseException thrown if there is an exception loading the
|
||||||
* database connection
|
* database connection
|
||||||
*/
|
*/
|
||||||
public Connection getConnection() throws DatabaseException {
|
public synchronized Connection getConnection() throws DatabaseException {
|
||||||
initialize();
|
initialize();
|
||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -206,7 +206,6 @@ public final class CveDB implements AutoCloseable {
|
|||||||
public CveDB(Settings settings) throws DatabaseException {
|
public CveDB(Settings settings) throws DatabaseException {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
connectionFactory = new ConnectionFactory(settings);
|
connectionFactory = new ConnectionFactory(settings);
|
||||||
connectionFactory.initialize();
|
|
||||||
open();
|
open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,11 +113,12 @@ public class NvdCveUpdater implements CachedWebDataSource {
|
|||||||
if (isUpdateConfiguredFalse()) {
|
if (isUpdateConfiguredFalse()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
H2DBLock dbupdate = null;
|
H2DBLock dblock = null;
|
||||||
try {
|
try {
|
||||||
if (ConnectionFactory.isH2Connection(settings)) {
|
if (ConnectionFactory.isH2Connection(settings)) {
|
||||||
dbupdate = new H2DBLock(settings);
|
dblock = new H2DBLock(settings);
|
||||||
dbupdate.lock();
|
LOGGER.debug("locking for update");
|
||||||
|
dblock.lock();
|
||||||
}
|
}
|
||||||
initializeExecutorServices();
|
initializeExecutorServices();
|
||||||
dbProperties = cveDb.getDatabaseProperties();
|
dbProperties = cveDb.getDatabaseProperties();
|
||||||
@@ -142,8 +143,8 @@ public class NvdCveUpdater implements CachedWebDataSource {
|
|||||||
} catch (H2DBLockException ex) {
|
} catch (H2DBLockException ex) {
|
||||||
throw new UpdateException("Unable to obtain an exclusive lock on the H2 database to perform updates", ex);
|
throw new UpdateException("Unable to obtain an exclusive lock on the H2 database to perform updates", ex);
|
||||||
} finally {
|
} finally {
|
||||||
if (dbupdate != null) {
|
if (dblock != null) {
|
||||||
dbupdate.release();
|
dblock.release();
|
||||||
}
|
}
|
||||||
shutdownExecutorServices();
|
shutdownExecutorServices();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ public class H2DBLock {
|
|||||||
try {
|
try {
|
||||||
final File dir = settings.getDataDirectory();
|
final File dir = settings.getDataDirectory();
|
||||||
lockFile = new File(dir, "dc.update.lock");
|
lockFile = new File(dir, "dc.update.lock");
|
||||||
|
if (!lockFile.getParentFile().isDirectory() && !lockFile.mkdir()) {
|
||||||
|
throw new H2DBLockException("Unable to create path to data directory.");
|
||||||
|
}
|
||||||
if (lockFile.isFile() && getFileAge(lockFile) > 5 && !lockFile.delete()) {
|
if (lockFile.isFile() && getFileAge(lockFile) > 5 && !lockFile.delete()) {
|
||||||
LOGGER.warn("An old db update lock file was found but the system was unable to delete "
|
LOGGER.warn("An old db update lock file was found but the system was unable to delete "
|
||||||
+ "the file. Consider manually deleting {}", lockFile.getAbsolutePath());
|
+ "the file. Consider manually deleting {}", lockFile.getAbsolutePath());
|
||||||
@@ -92,6 +95,7 @@ public class H2DBLock {
|
|||||||
if (!lockFile.exists() && lockFile.createNewFile()) {
|
if (!lockFile.exists() && lockFile.createNewFile()) {
|
||||||
file = new RandomAccessFile(lockFile, "rw");
|
file = new RandomAccessFile(lockFile, "rw");
|
||||||
lock = file.getChannel().lock();
|
lock = file.getChannel().lock();
|
||||||
|
LOGGER.debug("Lock file created ({})", Thread.currentThread().getName());
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.trace("Expected error as another thread has likely locked the file", ex);
|
LOGGER.trace("Expected error as another thread has likely locked the file", ex);
|
||||||
@@ -106,7 +110,7 @@ public class H2DBLock {
|
|||||||
}
|
}
|
||||||
if (lock == null || !lock.isValid()) {
|
if (lock == null || !lock.isValid()) {
|
||||||
try {
|
try {
|
||||||
LOGGER.debug("Sleeping thread {} for 5 seconds because we could not obtain the update lock.",
|
LOGGER.debug("Sleeping thread {} for 5 seconds because an exclusive lock on the database could not be obtained",
|
||||||
Thread.currentThread().getName());
|
Thread.currentThread().getName());
|
||||||
Thread.sleep(5000);
|
Thread.sleep(5000);
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
@@ -121,6 +125,7 @@ public class H2DBLock {
|
|||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new H2DBLockException(ex.getMessage(), ex);
|
throw new H2DBLockException(ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,6 +153,7 @@ public class H2DBLock {
|
|||||||
lockFile.deleteOnExit();
|
lockFile.deleteOnExit();
|
||||||
}
|
}
|
||||||
lockFile = null;
|
lockFile = null;
|
||||||
|
LOGGER.debug("Lock released ({})", Thread.currentThread().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user