Class CleanupScanUnitStorage

java.lang.Object
org.exoplatform.addons.documents.cleanup.storage.CleanupScanUnitStorage

@Component public class CleanupScanUnitStorage extends Object
RDBMS storage of the dry-run scan units: the only layer touching the scan-unit DAO, mapping entities to simple domain models. No business logic — the partitioning policy lives in CleanupConstants, the orchestration in CleanupScanService.
  • Field Details

    • MAX_REPORTED_EVAL_FAILURES

      public static final int MAX_REPORTED_EVAL_FAILURES
      Units carrying evaluation failures reported at once. A repository-wide problem makes EVERY unit fail, and a campaign plans one per space — the total is carried separately, so this bound truncates the detail and never the count.
      See Also:
  • Constructor Details

    • CleanupScanUnitStorage

      public CleanupScanUnitStorage()
  • Method Details

    • planUnits

      public void planUnits(long campaignId, List<String> unitPaths)
      Plans the units of a campaign, inserting as PENDING the paths not recorded yet and SKIPPING those already there: one paths query plus one saveAll, exactly like CleanupCampaignStorage#saveCandidates, backed by the UK_DOC_CLEANUP_SCAN_UNIT_PATH unique constraint. Safe — and meant — to be called on every resume: a re-plan never duplicates a unit, and never resets the checkpoint of a unit already walked.
      Parameters:
      campaignId - campaign identifier
      unitPaths - planned unit paths
    • getUnitsToProcess

      public List<CleanupScanUnit> getUnitsToProcess(long campaignId, long maxAttemptCount)
      The work list of a run: everything but DONE, MINUS the settled-failed units — the ones that FAILED after spending every walk attempt they had. Excluding them is what actually BOUNDS the retry: the attempt count is spent by updateUnitFailure(long, String) when the writer records a walk's FAILED outcome, so a unit left in the work list past the bound keeps being re-walked at full cost on every watchdog tick and its ATTEMPT_COUNT grows without end.

      The exclusion is STATE-AWARE, and must stay so: it is state = FAILED AND attemptCount >= maxAttemptCount, NEVER a bare attemptCount < maxAttemptCount. The counter only moves on a RECORDED failure, so it can only reach the bound on a unit whose state is FAILED — but the state condition is what keeps the rule honest against any later writer of the counter, and it is what the completion check mirrors (see CleanupScanService#completeCampaign, which settles a campaign only once every unit is DONE or settled-failed).

      The mirror image of countSettledFailedUnits(long, long), and it must stay so: exactly the units that no longer hold completion back are the units no longer walked, and a unit that FAILED with attempts left is on the other side of BOTH rules — still walked, still unsettled — which is what lets a transient JCR failure heal itself.

      Parameters:
      campaignId - campaign identifier
      maxAttemptCount - attempts a unit may spend, the first walk included
      Returns:
      the units of the campaign still to process, oldest id first
    • countUnits

      public long countUnits(long campaignId)
    • countUnitsByState

      public long countUnitsByState(long campaignId, CleanupScanUnitState state)
    • countSettledFailedUnits

      public long countSettledFailedUnits(long campaignId, long maxAttemptCount)
      Failed units of a campaign that spent every walk attempt they had — the SETTLED ones, which no longer hold the completion of the dry-run back.
      Parameters:
      campaignId - campaign identifier
      maxAttemptCount - attempts a unit may spend, the first walk included
      Returns:
      the number of settled-failed units
    • countFailuresByReason

      public List<CleanupFailureGroup> countFailuresByReason(long campaignId)
      Per-reason counts of a campaign's FAILED units, from ONE grouped aggregate query — the unit-level twin of CleanupCampaignStorage#countFailuresByReason. The retryable flag of each group is left to its default: what is worth re-attempting is a Service rule, not a query's (see CleanupFailureGroup).
      Parameters:
      campaignId - campaign identifier
      Returns:
      one group per distinct failure reason, empty when no unit of the campaign failed
    • getUnitProgress

      public CleanupScanUnitProgress getUnitProgress(long campaignId, long maxAttemptCount)
      Per-unit breakdown of a campaign's dry run, for the console to tell a scan that RESUMES from one that is STUCK — the node percentage cannot, see CleanupScanUnitProgress.

      Four aggregate queries and ONE bounded row fetch, never the unit rows: the state counts come grouped, the settled-failed count reuses the very query the terminal transition asks (so the console cannot disagree with it about what "settled" means), and only the RUNNING units are materialized.

      Parameters:
      campaignId - campaign identifier
      maxAttemptCount - attempts a unit may spend, the first walk included
      Returns:
      the breakdown, with a zeroed one for a campaign that has no unit
    • deleteUnits

      public void deleteUnits(long campaignId)
      Drops the unit rows of a campaign being deleted. NOT a reset: a campaign whose units are gone re-plans from scratch, so this is never called on one that can still be resumed.
      Parameters:
      campaignId - campaign identifier
    • getOrphanUnitCampaignIds

      public List<Long> getOrphanUnitCampaignIds()
      Campaign ids whose unit rows outlived their campaign row — see CleanupScanUnitDAO#findOrphanCampaignIds.
      Returns:
      the orphaned campaign ids, empty when there is nothing to sweep
    • updateUnitState

      public void updateUnitState(long unitId, CleanupScanUnitState state)
    • claimUnit

      public void claimUnit(long unitId)
      CLAIMS a unit for a walk: a PURE RUNNING flip, spending NOTHING. The walk attempt is spent by updateUnitFailure(long, String) — where a walk is recorded as having actually FAILED — never here: every unit of the work list is claimed up front before any reader starts, so a claim-time counter charged interruptions (a JVM restart mid-scan re-claims every remaining unit, the ones no reader ever reached included) to the very budget meant to bound genuine failures.
      Parameters:
      unitId - unit identifier
    • updateUnitFailure

      public void updateUnitFailure(long unitId, String failureReason)
      Marks a unit FAILED with its localizable reason, truncated to the column width (see MAX_FAILURE_REASON_LENGTH) — and SPENDS the walk attempt, in the same write. Counting it here rather than at claim time is what makes the attempt counter mean "walks that really failed": only a walk that reached a FAILED outcome moves a unit toward settled, so a run interrupted a dozen times still leaves the full retry budget, while the third recorded failure settles the unit exactly as CleanupScanService#MAX_SCAN_UNIT_ATTEMPTS promises.
      Parameters:
      unitId - unit identifier
      failureReason - localizable message code of the failure
    • updateUnitProgress

      public void updateUnitProgress(long unitId, String lastScannedPath, long scannedCount, CleanupNodeFailures failures)
      Checkpoints a unit and folds in the nodes the batch could not evaluate, in the SAME entity write: one load and one save per batch, exactly as before the failures existed.
      Parameters:
      unitId - unit identifier
      lastScannedPath - resume checkpoint of the unit
      scannedCount - absolute scanned count of the unit
      failures - nodes this batch could not evaluate, null or empty when it lost none
    • sumEvalFailureCount

      public long sumEvalFailureCount(long campaignId)
      Parameters:
      campaignId - campaign identifier
      Returns:
      nodes the campaign's scan walked but could not evaluate, summed over its units
    • getUnitsWithEvalFailures

      public List<CleanupScanUnit> getUnitsWithEvalFailures(long campaignId, int limit)
      Parameters:
      campaignId - campaign identifier
      limit - most units to return
      Returns:
      the units that lost at least one node, worst first
    • updateUnitTotal

      public void updateUnitTotal(long unitId, long totalCount)
    • sumScannedCount

      public long sumScannedCount(long campaignId)
    • sumTotalCount

      public long sumTotalCount(long campaignId)