Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Database transactions should be rolled back when committing fails #2677

Closed
2 tasks done
nscuro opened this issue Apr 16, 2023 · 3 comments · Fixed by #3711
Closed
2 tasks done

Database transactions should be rolled back when committing fails #2677

nscuro opened this issue Apr 16, 2023 · 3 comments · Fixed by #3711
Labels
enhancement New feature or request technical debt
Milestone

Comments

@nscuro
Copy link
Member

nscuro commented Apr 16, 2023

Current Behavior

The persist methods provided by AbstractAlpineQueryManager and inherited by DT's QueryManager do not rollback the active transaction when committing of the same fails. For example persist(T):

/**
 * Persists the specified PersistenceCapable object.
 * @param object a PersistenceCapable object
 * @param <T> the type to return
 * @return the persisted object
 */
@SuppressWarnings("unchecked")
public <T> T persist(T object) {
    pm.currentTransaction().begin();
    pm.makePersistent(object);
    pm.currentTransaction().commit();
    pm.getFetchPlan().setDetachmentOptions(FetchPlan.DETACH_LOAD_FIELDS);
    pm.refresh(object);
    return object;
}

Because none of those methods check whether a transaction is already active, and always start a new one instead (via PersistenceManager#currentTransaction()#begin), all operations following the initial failure with also fail with:

NucleusTransactionException: Invalid state. Transaction has already started

This can happen in situations similar to this one, where a single QueryManager instance is shared across multiple operations, and a single operation failing does not abort the overall execution:

try (final QueryManager qm = new QueryManager()) {
    final List<Project> projects = qm.getAllProjects(true);
    for (final Project project: projects) {
        final List<Component> components = qm.getAllComponents(project);
        for (final Component component: components) {
            try {
                doStuff(qm, component);
            } catch (Exception e) {
                LOGGER.warn("Doing stuff with component %s failed".formatted(component.getUuid()));
            }
        }
    }
}

If the first invocation of doStuff fails on commit, all other invocations will fail as well.

Proposed Behavior

Database transactions should be rolled back when committing fails.

Checklist

@nscuro nscuro added the enhancement New feature or request label Apr 16, 2023
@nscuro
Copy link
Member Author

nscuro commented Apr 16, 2023

We already have QueryManager#runInTransaction that performs proper rollbacks, but majority of the code base uses QueryManager#persist.

public void runInTransaction(final Runnable runnable) {
final Transaction trx = pm.currentTransaction();
try {
trx.begin();
runnable.run();
trx.commit();
} finally {
if (trx.isActive()) {
trx.rollback();
}
}
}

nscuro added a commit to nscuro/dependency-track that referenced this issue Apr 16, 2023
…positoryMetaAnalyzerTask`

The task works in such a way that a single `QueryManager` (and thus DN `ExecutionContext` and associated transaction) is shared across analyses of multiple components. Failure to analyze one component does not abort the overall analysis for all components.

Due to missing transaction rollbacks, the `RepositoryMetaAnalyzerTask` could end up in a situation where the `QueryManager`s active transaction failed to commit for one component, such that persisting of results for all following components would fail with `NucleusTransactionException: Invalid state. Transaction has already started`.

This fix is a mere workaround for the missing rollback of the `persist` method. DependencyTrack#2677 has been raised to address this for the entire application.

Signed-off-by: nscuro <nscuro@protonmail.com>
@nscuro nscuro added this to the 4.12 milestone May 15, 2024
@nscuro
Copy link
Member Author

nscuro commented May 15, 2024

Resolved in Alpine 2.2.6 via stevespringett/Alpine#552.

nscuro added a commit to nscuro/dependency-track that referenced this issue May 15, 2024
Signed-off-by: nscuro <nscuro@protonmail.com>
nscuro added a commit that referenced this issue May 15, 2024
Copy link
Contributor

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request technical debt
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant