fmorillo7694 opened a new issue, #18435:
URL: https://github.com/apache/iceberg/issues/18435

   ### Apache Iceberg version
   
   1.12.0 (latest release)
   
   ### Query engine
   
   Flink
   
   ### Please describe the bug 🐞
   
   `ConvertEqualityDeletes` (new in 1.12.0) holds the Flink-maintained 
maintenance lock forever once any other maintenance task on the same table has 
run. After that, neither task runs again.
   
   **Environment**
   
   - Iceberg 1.12.0, `iceberg-flink-runtime-2.3-1.12.0.jar`, Flink 2.3.0
   - `IcebergSink` (`table.exec.iceberg.use-v2-sink = true`), maintenance 
configured through `flink-maintenance.*` table options
   - Default Flink-maintained lock (no `flink-maintenance.lock.type`)
   - format-version 3, upsert table with a primary key, parallelism 1, REST 
catalog
   - The code involved is unchanged on `main`
   
   **Reproduce**
   
   ```sql
   SET 'table.exec.iceberg.use-v2-sink' = 'true';
   SET 'execution.checkpointing.interval' = '15s';
   
   CREATE TABLE cat.db.t (
     id BIGINT, v STRING, PRIMARY KEY (id) NOT ENFORCED
   ) WITH (
     'format-version' = '3',
     'write.upsert.enabled' = 'true',
     'flink-maintenance.convert-equality-deletes.enabled' = 'true',
     'flink-maintenance.convert-equality-deletes.schedule.commit-count' = '1',
     'flink-maintenance.rewrite.enabled' = 'true',
     'flink-maintenance.rewrite.schedule.commit-count' = '2',
     'flink-maintenance.rate-limit-seconds' = '5',
     'flink-maintenance.lock-check-delay-seconds' = '5'
   );
   
   CREATE TEMPORARY TABLE src (id BIGINT, v STRING) WITH (
     'connector' = 'datagen', 'rows-per-second' = '1000',
     'fields.id.min' = '1', 'fields.id.max' = '10000'
   );
   
   INSERT INTO cat.db.t SELECT id, v FROM src;
   ```
   
   **Expected**
   
   Both tasks keep running, one at a time under the shared lock. The 
ConvertEqualityDeletes section of `docs/docs/flink-maintenance.md` says the 
shared maintenance lock keeps it safe alongside compaction.
   
   **Actual**
   
   - The converter runs one cycle and the lock is released (`Received lock 
released event`).
   - `RewriteDataFiles [0]` then runs and finishes: `LockRemoverOperator` logs 
`Processing result ... RewriteDataFiles [0]`. No `Received lock released event` 
follows.
   - From then on, `TriggerManagerOperator` logs `Failed to acquire lock. 
Delaying task to ...` on every check (21 times in a 120s run, 33 in a 180s 
run), and `concurrentRunThrottled` keeps growing.
   - Neither task runs again. `processedStagingSnapshotNum` stays at 0, and 
equality-delete files pile up: 48 after 120s, 96 after 180s.
   - With the converter as the only maintenance task, the same table and load 
ran normally in five runs: 31 conversion commits, no errors.
   
   **Cause, as far as we can tell**
   
   1. Every task's pipeline sees every trigger's watermark. `Filter <i>` 
(`TableMaintenance.java:329-337`) drops other tasks' records but not their 
watermarks. All task outputs are unioned into `Lock remover` (`:349-365`).
   2. With the Flink-maintained lock, `LockRemoverOperator` releases only from 
`processWatermark`, by sending `LockReleaseEvent(mark)` 
(`LockRemoverOperator.java:106-114`). `processElement` only updates metrics. 
`TriggerManagerOperator.handleLockRelease` clears the lock only when `timestamp 
>= lockTime` (`:254-261`).
   3. `EqualityConvertCommitter.processWatermark` returns without forwarding 
when `planResult == null` (`EqualityConvertCommitter.java:151-157`). 
`planResult` is set only from the converter's own planner, so a watermark from 
another task's trigger is dropped.
   4. The union's minimum watermark therefore stays at the converter's last 
forwarded value, and the lock taken for the other task is never released. Only 
a new converter cycle would advance that watermark, and starting one needs the 
lock.
   
   The hold-back was added in #17038 to fix a race where the planner's 
mid-cycle phase watermarks released the lock early. In-flight cycles are still 
held back correctly. The problem is the `planResult == null` case.
   
   **Probably also affected (from reading the code, not reproduced)**
   
   - The converter combined with `expire-snapshots` or `delete-orphan-files`. 
Both of those branches forward every watermark, like rewrite.
   - A converter-only table restored from a checkpoint or savepoint. 
`TriggerManagerOperator.initializeState` takes the lock and emits 
`Trigger.recovery(...)`, which has no task id. Only its watermark reaches the 
converter committer, which drops it, so the recovery lock would never be 
released.
   
   **Possible fix**
   
   - Make the committer forward watermarks whenever no conversion cycle is in 
flight. A plain `if (planResult == null) forward` would bring back the #17038 
race: the planner emits phase watermarks (`advancePhase`) before it emits the 
plan record. One option is for the planner to emit a cycle-start marker on the 
metadata stream before its first `advancePhase`. The committer would then hold 
watermarks only between that marker and the commit.
   - As an extra safeguard, `LockRemoverOperator.processElement` could also 
send `LockReleaseEvent(taskResult.startEpoch())`, as the legacy `LockRemover` 
does on `TaskResult`. That isn't enough on its own. `TaskResultAggregator` 
emits the result before it forwards the watermark, so on the normal path the 
watermark's release event would then reach `handleLockRelease` with `lockTime 
== null` and fail its `Preconditions.checkArgument` 
(`TriggerManagerOperator.java:255`). That check would have to become a no-op 
for an already-released lock. It also wouldn't help the restore case, which is 
released by watermark only.
   
   Neither `TestMaintenanceE2E` nor `TestIcebergSinkTableMaintenance` runs 
`ConvertEqualityDeletes` together with another task. A test that runs both and 
checks that each completes at least twice would catch this.
   
   ### Willingness to contribute
   
   - [ ] I can contribute a fix for this bug independently
   - [ ] I would be willing to contribute a fix for this bug with guidance from 
the Iceberg community
   - [ ] I cannot contribute a fix for this bug at this time
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to