Interface Store

All Known Implementing Classes:
FileStore

@Restricted(org.kohsuke.accmod.restrictions.NoExternalUse.class) public interface Store
Durable, build-independent plugin store under $JENKINS_HOME/batch-control/ (layout in docs/ARCHITECTURE.md section 5). Records are append-only; there is no update or delete API (retention cleanup is the only deletion path; config snapshots are working data, not records, and keep only the latest version).

All methods throw UncheckedIOException on I/O failure, except that a failed save of an XML entity (request, grant, incident, activation) throws StoreWriteException and leaves nothing behind (D-72b (2), security-35 S-35-03).

  • Field Details

    • MAX_SCANNED_RECORDS

      static final int MAX_SCANNED_RECORDS
      Default maxScanned of the page queries: the per-request record cap.
      See Also:
  • Method Details

    • get

      static Store get()
      The store every caller uses (D-44). This is the one place that names the implementation, so a database-backed store (D-11) replaces this line and nothing else.
    • warmUp

      void warmUp()
      Prepares derived in-memory data (indexes, caches) ahead of the first request so no later save pays for it. Called once at startup.
    • saveRunRequest

      void saveRunRequest(RunRequest request)
      Writes (or rewrites, on a status transition) the request XML <id>.xml atomically. Never touches the request's typed values (D-74).
      Throws:
      StoreWriteException - when it cannot be written; nothing is left behind
    • saveNewRunRequest

      void saveNewRunRequest(RunRequest request, List<ParameterValue> values)
      Stores a new request (D-72, D-74): <id>.xml, then its typed values in <id>.values.xml when there are any (a request without parameters has no values file). Each file is written atomically; when either cannot be written, neither is left behind.
      Throws:
      StoreWriteException - when it cannot be stored; nothing is left behind
    • loadRunRequest

      RunRequest loadRunRequest(String id)
      Loads a request by id from <id>.xml, or returns null if it does not exist. Its typed values are never read here (D-74): this is the read for screens, badges, listings, listeners and periodic work.
    • loadRunRequestValues

      @CheckForNull List<ParameterValue> loadRunRequestValues(String id)
      The typed values of request id from <id>.values.xml (D-74), or null when there is no values file (the request has no parameters, or its values were deleted when its run started or it ended). Only for approving, submitting, recovering and disposing of a request. An element that could not be loaded may be null.
      Throws:
      UncheckedIOException - when the file exists but cannot be read
    • deleteRunRequestValues

      void deleteRunRequestValues(String id)
      Deletes the typed values of request id (<id>.values.xml), when the approved run starts or the request ends (D-72b (5), D-74); nothing happens when there are none.
    • listRunRequests

      List<RunRequest> listRunRequests()
      Loads every stored run request, sorted by creation time. A file that cannot be read (corrupt, or not readable at all) is left out with a warning, so one such file never breaks a listing.
    • listOpenRunRequests

      default List<RunRequest> listOpenRunRequests()
      Loads the PENDING and APPROVED run requests only, sorted by creation time. Served from the in-memory entity index, so closed requests are never read; this is what the per-minute expiry work, startup recovery and rename invalidation iterate.

      An open request whose file cannot be read (permission, I/O error or damaged content) is left out with a warning naming it, so it is never expired, approved, run, recovered or counted while unreadable, and it never breaks the listing for the others. Its index entry is kept, so the next listing reads it again and it is back as soon as it can be read.

    • listOpenRunRequests

      List<RunRequest> listOpenRunRequests(Consumer<String> unreadable)
      As listOpenRunRequests(), and hands the id of every open request left out because its file cannot be read to unreadable, for a caller that must act on it once it can be read (an invalidation it would otherwise miss).
    • listRunRequestSummaries

      List<RequestSummary> listRunRequestSummaries()
      The listing fields of every stored run request, sorted by id, from memory. A listing filters and pages on these and loads only the XML of the rows it renders.
    • hasRunRequestBy

      boolean hasRunRequestBy(String userId)
      Whether at least one stored run request, in any status, was filed by userId (D-38b). Answered from the in-memory entity index; no request file and no item is read.
    • saveGrantRequest

      void saveGrantRequest(GrantRequest request)
      Writes (or rewrites, on a status transition) the grant request XML atomically.
    • loadGrantRequest

      GrantRequest loadGrantRequest(String id)
      Loads a grant request by id, or returns null if it does not exist.
    • listGrantRequests

      List<GrantRequest> listGrantRequests()
      Loads every stored grant request, sorted by id (creation order).
    • listOpenGrantRequests

      List<GrantRequest> listOpenGrantRequests()
      Loads the PENDING grant requests only, sorted by id, via the entity index. An open request whose file cannot be read is left out with a warning and its index entry kept, as for listOpenRunRequests().
    • saveGrant

      void saveGrant(Grant grant)
      Writes (or rewrites, on revocation) the grant XML atomically.
    • loadGrant

      Grant loadGrant(String id)
      Loads a grant by id, or returns null if it does not exist.
    • listGrants

      List<Grant> listGrants()
      Loads every stored grant, sorted by id (creation order). A file that cannot be read (corrupt, or not readable at all) is left out with a warning: that grant confers nothing, and the permission checks of everyone else keep working.
    • saveActivationRequest

      void saveActivationRequest(ActivationRequest request)
      Writes (or rewrites, on a status transition) the activation request XML atomically.
    • loadActivationRequest

      ActivationRequest loadActivationRequest(String id)
      Loads an activation request by id, or returns null if it does not exist.
    • listActivationRequests

      List<ActivationRequest> listActivationRequests()
      Loads every stored activation request, sorted by id (creation order).
    • listOpenActivationRequests

      default List<ActivationRequest> listOpenActivationRequests()
      Loads the PENDING activation requests only, sorted by id, via the entity index. An open request whose file cannot be read is left out with a warning and its index entry kept, as for listOpenRunRequests().
    • listOpenActivationRequests

      List<ActivationRequest> listOpenActivationRequests(Consumer<String> unreadable)
      As listOpenActivationRequests(), and hands the id of every open request left out because its file cannot be read to unreadable.
    • hasActivationRequestBy

      boolean hasActivationRequestBy(String userId)
      Whether at least one stored activation or hold request, in any status, was filed by userId (D-38b). Answered from the in-memory entity index.
    • saveActivationState

      void saveActivationState(ActivationState state)
      Writes the activation state of a job atomically to activations/<PathCodec-encoded full name>.xml; the file name comes from ActivationState.getJobFullName().
    • loadActivationState

      ActivationState loadActivationState(String jobFullName)
      The stored activation state of a job, or null if none exists.
    • listActivationStates

      List<ActivationState> listActivationStates()
      Every stored activation state (unordered).
    • deleteActivationState

      boolean deleteActivationState(String jobFullName)
      Removes the activation state of a job; true if one existed.
    • isActivationSchemaMarked

      boolean isActivationSchemaMarked()
      Whether the one-time upgrade seeding marker activations/.schema exists.
    • markActivationSchema

      void markActivationSchema()
      Writes the upgrade seeding marker activations/.schema (atomically).
    • saveConfigSnapshot

      void saveConfigSnapshot(String jobFullName, String configXml)
      Stores the latest config.xml snapshot of a job (diff baseline; only the latest version is kept, ARCHITECTURE section 5).
    • loadConfigSnapshot

      String loadConfigSnapshot(String jobFullName)
      The stored config snapshot text of a job, or null if none exists.
      Throws:
      UncheckedIOException - when a snapshot exists but cannot be read, also when something other than a file is in its place
    • hasConfigSnapshot

      boolean hasConfigSnapshot(String jobFullName)
      Whether anything is stored where the config snapshot of a job belongs: a snapshot, or something else in its place (which loadConfigSnapshot(java.lang.String) refuses). Nothing is read, so seeding the missing snapshots of every item costs one file system lookup per item.
    • deleteConfigSnapshot

      void deleteConfigSnapshot(String jobFullName)
      Removes the config snapshot of a job (after deletion, rename or move).
    • appendRunRecord

      void appendRunRecord(RunRecord record)
      Appends one run record to the monthly JSONL bucket derived from its start time. The line carries appendedAt (D-81): the record's own RunRecord.getAppendedAt() when the caller set it, else the plugin clock's instant of this append.
    • listRunRecords

      List<RunRecord> listRunRecords(YearMonth month)
      Reads every run record of the given month (empty list if the month file is absent).
    • pageRunRecords

      RecordPage<RunRecord> pageRunRecords(Collection<YearMonth> months, Period period, Predicate<? super RunRecord> filter, int offset, int limit, int maxScanned)
      One page of the run records of months that match filter, newest first (start time, then run id). Reads newest first and stops after maxScanned records, so the cost of a page load is bounded whatever a month holds; only records whose start time lies inside period count toward maxScanned (security-10 S-03).
      Parameters:
      offset - matches to skip (page index times page size)
      limit - rows to return
      maxScanned - records to read at most; see MAX_SCANNED_RECORDS
    • runMonthStats

      RunMonthStats runMonthStats(YearMonth month)
      Run counters of one month, maintained incrementally from the bucket.
    • appendChangeRecord

      void appendChangeRecord(ChangeRecord record)
      Appends one change record to the monthly JSONL bucket derived from its timestamp.
    • listChangeRecords

      List<ChangeRecord> listChangeRecords(YearMonth month)
      Reads every change record of the given month (empty list if the month file is absent).
    • pageChangeRecords

      RecordPage<ChangeRecord> pageChangeRecords(Collection<YearMonth> months, Predicate<? super ChangeRecord> filter, int offset, int limit, int maxScanned)
    • pageChangeRecords

      RecordPage<ChangeRecord> pageChangeRecords(Collection<YearMonth> months, Period period, Predicate<? super ChangeRecord> filter, int offset, int limit, int maxScanned)
    • grantRevokeRecordsSince

      RecordPage<ChangeRecord> grantRevokeRecordsSince(Instant since, Set<String> grantIds, Predicate<? super ChangeRecord> boundary)
      S-39-03: every GRANT_REVOKE change record of a grant in grantIds with a time at or after since, newest first, for re-ending windows at startup (D-74). Bounded by time, not by a record count: the change log is read back only to the first record appended before since, and every record after it is read, however many there are. The page is truncated when that could not be done completely.

      Reading also stops at the first record before since that boundary accepts (T-SEC-109): the caller's statement that no line appended before that record can be the end of any window in grantIds, so the append-order slack is not read past it.

      Throws:
      UncheckedIOException - when the change log cannot be read
    • createIncident

      void createIncident(Incident incident)
      Persists a freshly opened incident: writes incidents/<id>.xml and appends the monthly index line (incidents/index/YYYY-MM.jsonl, bucket derived from the incident's creation time).
    • saveIncident

      void saveIncident(Incident incident)
      Rewrites an existing incident's XML atomically (handling transitions, links).
    • loadIncident

      Incident loadIncident(String id)
      Loads an incident by id, or returns null if it does not exist.
    • listIncidents

      List<Incident> listIncidents(YearMonth month)
      Loads every incident created in the given month via the monthly index, in index (creation) order. Index lines whose XML has been deleted are skipped.
    • pageIncidents

      RecordPage<Incident> pageIncidents(Collection<YearMonth> months, Period period, Predicate<? super IncidentSummary> indexFilter, Predicate<? super Incident> filter, int offset, int limit, int maxScanned)
      As pageRunRecords(java.util.Collection<java.time.YearMonth>, io.jenkins.plugins.batchcontrol.store.Period, java.util.function.Predicate<? super io.jenkins.plugins.batchcontrol.model.RunRecord>, int, int, int) for incidents, walking the monthly index newest first (creation time, then id); every index line read counts against maxScanned. indexFilter is tested on the index line and an incident's XML is loaded only when it passes (security-10 S-06); filter then sees the loaded incident.
    • listStoredMonths

      List<YearMonth> listStoredMonths()
      Every month for which any record bucket exists (runs, changes or incident index), sorted ascending. Used by retention cleanup.
    • listStoredMonths

      List<YearMonth> listStoredMonths(Period period)
      #33: the stored month buckets (as listStoredMonths()) that may hold a record whose timestamp lies in period, whatever time zone the plugin clock had when the record was written: a bucket is named by the month of the record in the zone of its writer (SPEC 4), so after the controller's zone changed, a record near a month boundary sits in the neighbouring month's bucket. A date-range query reads these buckets and keeps the records inside period; existing files need no migration. A bucket outside the period's own months is included only when the period comes within the largest zone offset (18 hours) of it.
    • deleteMonth

      boolean deleteMonth(YearMonth month)
      Deletes every record bucket of the given month: the runs and changes JSONL files, the diff patches of that month's change records, the incident XMLs listed in that month's index and the index file itself. This is the ONLY deletion path of the store (SPEC item 4: append-only apart from retention cleanup).
      Returns:
      true if anything was deleted
    • deleteClosedEntitiesBefore

      RetentionResult deleteClosedEntitiesBefore(Instant cutoff)
      Retention of the XML entities: deletes closed run requests (not PENDING or APPROVED) and closed grant requests (not PENDING) whose last activity lies before cutoff, and grants that stopped conferring anything (expiry or revocation) before it. A grant request is kept while a grant issued from it is kept. Each file is deleted under its own lock, so no store lock is held for longer than one deletion.