Skip to content

Commit

Permalink
Log deleted project info + fix nullPointerException (#1064)
Browse files Browse the repository at this point in the history
  • Loading branch information
sahibamittal authored Feb 19, 2025
1 parent c3a970f commit f42b707
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 10 deletions.
19 changes: 15 additions & 4 deletions src/main/java/org/dependencytrack/persistence/jdbi/ProjectDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import com.fasterxml.jackson.annotation.JsonAlias;
import jakarta.annotation.Nullable;
import org.jdbi.v3.core.mapper.reflect.ColumnName;
import org.jdbi.v3.json.Json;
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
import org.jdbi.v3.sqlobject.customizer.Bind;
Expand Down Expand Up @@ -228,7 +229,7 @@ record ConciseProjectMetricsRow(
""")
int deleteProject(@Bind final UUID projectUuid);

@SqlUpdate("""
@SqlQuery("""
WITH "CTE" AS (
SELECT "ID"
FROM "PROJECT"
Expand All @@ -239,10 +240,18 @@ record ConciseProjectMetricsRow(
DELETE
FROM "PROJECT"
WHERE "ID" IN (SELECT "ID" FROM "CTE")
RETURNING "NAME", "VERSION", "INACTIVE_SINCE", "UUID"
""")
int deleteInactiveProjectsForRetentionDuration(@Bind final Instant retentionCutOff, @Bind final int batchSize);
@RegisterConstructorMapper(DeletedProject.class)
List<DeletedProject> deleteInactiveProjectsForRetentionDuration(@Bind final Instant retentionCutOff, @Bind final int batchSize);

@SqlUpdate("""
record DeletedProject(@ColumnName("NAME") String name,
@ColumnName("VERSION") String version,
@ColumnName("INACTIVE_SINCE") Instant inactiveSince,
@ColumnName("UUID") UUID uuid) {
}

@SqlQuery("""
DELETE
FROM "PROJECT"
WHERE "PROJECT"."INACTIVE_SINCE" IS NOT NULL
Expand All @@ -255,8 +264,10 @@ record ConciseProjectMetricsRow(
ORDER BY "PROJECT"."INACTIVE_SINCE" DESC
LIMIT :versionCountThreshold
)
RETURNING "NAME", "VERSION", "INACTIVE_SINCE", "UUID"
""")
int retainLastXInactiveProjects(@Bind final String projectName, @Bind final int versionCountThreshold);
@RegisterConstructorMapper(DeletedProject.class)
List<DeletedProject> retainLastXInactiveProjects(@Bind final String projectName, @Bind final int versionCountThreshold);

@SqlQuery("""
SELECT "PROJECT"."NAME"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,25 +75,28 @@ private Statistics informLocked() {
assertLocked();
AtomicInteger numDeletedTotal = new AtomicInteger(0);

final String retentionType = withJdbiHandle(handle ->
handle.attach(ConfigPropertyDao.class).getValue(MAINTENANCE_PROJECTS_RETENTION_TYPE, String.class));
final var retentionType = withJdbiHandle(handle ->
handle.attach(ConfigPropertyDao.class).getOptionalValue(MAINTENANCE_PROJECTS_RETENTION_TYPE, String.class));

if (retentionType != null) {
if (!retentionType.isEmpty() && !retentionType.get().isEmpty()) {
int batchSize = 100;
if (retentionType.equals("AGE")) {
if (retentionType.get().equals("AGE")) {

final int retentionDays = withJdbiHandle(handle ->
handle.attach(ConfigPropertyDao.class).getValue(MAINTENANCE_PROJECTS_RETENTION_DAYS, Integer.class));
final Duration retentionDuration = Duration.ofDays(retentionDays);
Instant retentionCutOff = Instant.now().minus(retentionDuration);
Integer numDeletedLastBatch = null;
while (numDeletedLastBatch == null || numDeletedLastBatch > 0) {
numDeletedLastBatch = withJdbiHandle(
final var deletedProjectsBatch = withJdbiHandle(
batchHandle -> {
final var projectDao = batchHandle.attach(ProjectDao.class);
return projectDao.deleteInactiveProjectsForRetentionDuration(retentionCutOff, batchSize);
});
numDeletedLastBatch = deletedProjectsBatch.size();
numDeletedTotal.addAndGet(numDeletedLastBatch);
deletedProjectsBatch.forEach(deletedProject ->
LOGGER.info("Inactive project deleted: [name:%s, version:%s, inactive since:%s, uuid:%s]".formatted(deletedProject.name(), deletedProject.version(), deletedProject.inactiveSince(), deletedProject.uuid())));
}
} else {
final int versionCountThreshold = withJdbiHandle(handle ->
Expand All @@ -105,7 +108,10 @@ private Statistics informLocked() {
final var projectDao = batchHandle.attach(ProjectDao.class);
List<String> projectBatch = projectDao.getDistinctProjects(versionCountThreshold, batchSize);
for (var projectName : projectBatch) {
numDeletedTotal.addAndGet(projectDao.retainLastXInactiveProjects(projectName, versionCountThreshold));
final var deletedProjects = projectDao.retainLastXInactiveProjects(projectName, versionCountThreshold);
numDeletedTotal.addAndGet(deletedProjects.size());
deletedProjects.forEach(deletedProject ->
LOGGER.info("Inactive project deleted: [name:%s, version:%s, inactive since:%s, uuid:%s]".formatted(deletedProject.name(), deletedProject.version(), deletedProject.inactiveSince(), deletedProject.uuid())));
}
return projectBatch.size();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,24 @@ public void testWithProjectRetentionDisabled() {
assertThatNoException().isThrownBy(() -> task.inform(new ProjectMaintenanceEvent()));
assertThat(qm.getProjects()).isNotNull();
}

@Test
public void testWithProjectRetentionDisabledWithEmptyValue() {
qm.createConfigProperty(
MAINTENANCE_PROJECTS_RETENTION_TYPE.getGroupName(),
MAINTENANCE_PROJECTS_RETENTION_TYPE.getPropertyName(),
"",
MAINTENANCE_PROJECTS_RETENTION_TYPE.getPropertyType(),
MAINTENANCE_PROJECTS_RETENTION_TYPE.getDescription());

var project = new Project();
project.setName("acme-app");
project.setVersion("1.0.0");
project.setInactiveSince(DateUtil.parseShortDate("20100109"));
qm.persist(project);

final var task = new ProjectMaintenanceTask();
assertThatNoException().isThrownBy(() -> task.inform(new ProjectMaintenanceEvent()));
assertThat(qm.getProjects()).isNotNull();
}
}

0 comments on commit f42b707

Please sign in to comment.