feat: Add new TaskLockType KILL for embedded kill tasks - #19921
Conversation
Introduces a new KILL lock type that can coexist with all other lock types (EXCLUSIVE, SHARED, REPLACE, APPEND) but not with another KILL lock on an overlapping interval. Only tasks of type "kill" are permitted to acquire a KILL lock. UnusedSegmentsKiller's embedded kill task now uses KILL locking by default, allowing concurrent ingest tasks to proceed while unused segments are being deleted. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tests verify that a KILL lock can be acquired, released, and revoked for tasks that are never inserted into TaskStorage (the embedded kill task pattern used by UnusedSegmentsKiller). Specifically: - Acquire + release without task in storage unblocks the next acquirer - Lock is not restored after syncFromStorage (task not persisted) - Higher-priority kill task not in storage can revoke a lower-priority one - KILL lock coexists with other lock types held by persisted tasks Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add tests to SqlSegmentsMetadataQueryTest covering the validateSegmentsForMarkingAsUsed guard: - throws CONFLICT when kill is enabled and segment was updated before buffer period - succeeds when kill is enabled but segment was updated within buffer period - succeeds when kill is disabled regardless of how old the update time is - covers markSegmentAsUsed, markNonOvershadowedSegmentsAsUsed, and markAllNonOvershadowedSegmentsAsUsed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
FrankChen021
left a comment
There was a problem hiding this comment.
| Severity | Findings |
|---|---|
| P0 | 0 |
| P1 | 0 |
| P2 | 1 |
| P3 | 0 |
| Total | 1 |
Reviewed 35 of 35 changed files.
This is an automated review by Codex GPT-5.6-Luna(max)
| Map.of(Tasks.PRIORITY_KEY, Tasks.DEFAULT_EMBEDDED_KILL_TASK_PRIORITY), | ||
| Map.of( | ||
| Tasks.PRIORITY_KEY, Tasks.DEFAULT_EMBEDDED_KILL_TASK_PRIORITY, | ||
| Tasks.TASK_LOCK_TYPE, TaskLockType.KILL.name() |
There was a problem hiding this comment.
[P2] KILL locks incorrectly suppress compaction
The compaction duty reports active locks through getLockedIntervals, which includes this priority-25 KILL lock even though KILL is designed to coexist with compaction locks. Compatible intervals are consequently deferred while a kill task is active. Make lock reporting honor lock compatibility and add a regression test.
There was a problem hiding this comment.
Good catch! Addressed.
There was a problem hiding this comment.
Confirmed fixed at this head: getLockedIntervals now ignores KILL locks for non-KILL requests, with regression coverage. I reviewed all 37 changed files and found no additional issues.
| throw DruidException.forPersona(DruidException.Persona.OPERATOR) | ||
| .ofCategory(DruidException.Category.CONFLICT) | ||
| .build( | ||
| "Segment IDs[%s] cannot be marked as used since" | ||
| + " they were last updated more than [%s] ago and" | ||
| + " are now eligible for permanent deletion.", | ||
| expiredSegmentIds, bufferPeriod | ||
| ); |
There was a problem hiding this comment.
does this new restriction need to be in docs? perhaps in the properties table that describes what the buffer period is and what happens after the segment ages out of the buffer?
There was a problem hiding this comment.
documenting depends a lot on the outcome of my comment above related to only enforcing this when using embedded kill
There was a problem hiding this comment.
Hmm, I think we should document it either way (at least for embedded kill tasks).
| if (!managerConfig.getKillUnused().isEnabled()) { | ||
| // Do not verify the buffer period if embedded kill tasks are not enabled | ||
| return; | ||
| } |
There was a problem hiding this comment.
hmmm. do we really need to introduce this exception to the rule? Having the whole system opted into the new restriction about how long a segment can be unused before not being eligible to mark used seems less sconfusing
There was a problem hiding this comment.
Yeah, I started with that. But then I realized that the bufferPeriod config makes sense only when embedded kill is enabled, since the UnusedSegmentKillerConfig.bufferPeriod does not apply to regular kill tasks.
| throw new ISE("Unable to grant LockPosse to inactive Task [%s]", task.getId()); | ||
| } | ||
|
|
||
| if (request.getType() == TaskLockType.KILL && !KillUnusedSegmentsTask.TYPE.equals(task.getType())) { |
There was a problem hiding this comment.
so manually submitted kill tasks can use the kill lock type, as far as I can tell at least. is that acceptable?
There was a problem hiding this comment.
Yeah, this is on purpose but I see the problem. If we wanted to use the KILL lock type for manual kill tasks, we would also need to do the validation on mark-as-used even if embedded kill was disabled.
I don't see a clear way to do that, except maybe always honoring the bufferPeriod.
There was a problem hiding this comment.
Updated this to allow KILL locks only for embedded kill tasks.
|
Thanks for the review, @capistrant ! |
capistrant
left a comment
There was a problem hiding this comment.
thanks for responses to my questions and comments. looks good to me.
FrankChen021
left a comment
There was a problem hiding this comment.
I have reviewed the code for correctness, edge cases, concurrency, and integration risks; no issues found.
Reviewed 38 of 38 changed files.
This is an automated review by Codex GPT-5.6-Luna(max)
Description
This has been split from #19772 .
Instead of acquiring a lock for
markAsUsedandmarkAsUnusedAPIs (as it may potentially hamper ingestion),this patch tries to relax the locking requirements of a kill task and adds restrictions on the window for
markAsUsed.Changes
TaskLockType.KILLKILLlock to ensure that only a singlekilltask is working on a single datasource-intervalUnusedSegmentsKillerdoes not skip intervals with active ingestion.SegmentsMetadataManagerConfigintoSqlSegmentsMetadataQuery.killtask for that segment is in progress.SegmentMetadataTransactionFactoryto provide read-write transactions which do not use the segment metadata cache. This moves away the transaction creation logic fromIndexerSQLMetadataStorageCoordinatorto the transaction factory and reduces the number of call sites that create aSqlSegmentsMetadataQuery.This PR has: