Merge pull request #744 from ysoftdevs/cvedb-cache

Added some caching for CveDB in order to speedup some scans
This commit is contained in:
Jeremy Long
2017-05-26 07:37:57 -04:00
committed by GitHub

View File

@@ -24,6 +24,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
@@ -36,6 +37,7 @@ import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Set;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.collections.map.ReferenceMap;
import org.owasp.dependencycheck.data.cwe.CweDB;
import org.owasp.dependencycheck.dependency.Reference;
import org.owasp.dependencycheck.dependency.Vulnerability;
@@ -48,6 +50,8 @@ import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.commons.collections.map.AbstractReferenceMap.HARD;
import static org.apache.commons.collections.map.AbstractReferenceMap.SOFT;
import static org.owasp.dependencycheck.data.nvdcve.CveDB.PreparedStatementCveDb.*;
/**
@@ -91,6 +95,9 @@ public final class CveDB implements AutoCloseable {
*/
private final EnumMap<PreparedStatementCveDb, PreparedStatement> preparedStatements = new EnumMap<>(PreparedStatementCveDb.class);
@SuppressWarnings("unchecked")
private final Map<String, List<Vulnerability>> vulnerabilitiesForCpeCache = Collections.synchronizedMap(new ReferenceMap(HARD, SOFT));
/**
* The enum value names must match the keys of the statements in the
* statement bundles "dbStatements*.properties".
@@ -269,6 +276,7 @@ public final class CveDB implements AutoCloseable {
instance.usageCount -= 1;
if (instance.usageCount <= 0 && instance.isOpen()) {
instance.usageCount = 0;
clearCache();
instance.closeStatements();
try {
instance.connection.close();
@@ -474,6 +482,7 @@ public final class CveDB implements AutoCloseable {
* @param value the property value
*/
public synchronized void saveProperty(String key, String value) {
clearCache();
try {
try {
final PreparedStatement mergeProperty = getPreparedStatement(MERGE_PROPERTY);
@@ -498,6 +507,17 @@ public final class CveDB implements AutoCloseable {
}
}
/**
* Clears cache. Should be called whenever something is modified. While this is not the optimal cache eviction
* strategy, this is good enough for typical usage (update DB and then only read) and it is easier to maintain
* the code.
*
* It should be also called when DB is closed.
*/
private void clearCache() {
vulnerabilitiesForCpeCache.clear();
}
/**
* Retrieves the vulnerabilities associated with the specified CPE.
*
@@ -506,6 +526,13 @@ public final class CveDB implements AutoCloseable {
* @throws DatabaseException thrown if there is an exception retrieving data
*/
public synchronized List<Vulnerability> getVulnerabilities(String cpeStr) throws DatabaseException {
final List<Vulnerability> cachedVulnerabilities = vulnerabilitiesForCpeCache.get(cpeStr);
if (cachedVulnerabilities != null) {
LOGGER.debug("Cache hit for {}", cpeStr);
return cachedVulnerabilities;
} else {
LOGGER.debug("Cache miss for {}", cpeStr);
}
final VulnerableSoftware cpe = new VulnerableSoftware();
try {
cpe.parseName(cpeStr);
@@ -554,6 +581,7 @@ public final class CveDB implements AutoCloseable {
} finally {
DBUtils.closeResultSet(rs);
}
vulnerabilitiesForCpeCache.put(cpeStr, vulnerabilities);
return vulnerabilities;
}
@@ -633,6 +661,7 @@ public final class CveDB implements AutoCloseable {
* @throws DatabaseException is thrown if the database
*/
public synchronized void updateVulnerability(Vulnerability vuln) throws DatabaseException {
clearCache();
try {
int vulnerabilityId = 0;
final PreparedStatement selectVulnerabilityId = getPreparedStatement(SELECT_VULNERABILITY_ID);
@@ -799,6 +828,7 @@ public final class CveDB implements AutoCloseable {
* ensure orphan entries are removed.
*/
public synchronized void cleanupDatabase() {
clearCache();
try {
final PreparedStatement ps = getPreparedStatement(CLEANUP_ORPHANS);
if (ps != null) {
@@ -934,6 +964,7 @@ public final class CveDB implements AutoCloseable {
* Deletes unused dictionary entries from the database.
*/
public synchronized void deleteUnusedCpe() {
clearCache();
PreparedStatement ps = null;
try {
ps = connection.prepareStatement(statementBundle.getString("DELETE_UNUSED_DICT_CPE"));
@@ -956,6 +987,7 @@ public final class CveDB implements AutoCloseable {
* @param product the CPE product
*/
public synchronized void addCpe(String cpe, String vendor, String product) {
clearCache();
PreparedStatement ps = null;
try {
ps = connection.prepareStatement(statementBundle.getString("ADD_DICT_CPE"));