{"record":{"id":"d9ef433f373cff6b","repo":"apache/iceberg","slug":"interrupted-during-isheld","errorCode":null,"errorMessage":"Interrupted during isHeld","messagePattern":"Interrupted during isHeld","errorType":"exception","errorClass":"UncheckedInterruptedException","httpStatus":null,"severity":"warning","filePath":"flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java","lineNumber":227,"sourceCode":"    }\n\n    @SuppressWarnings(\"checkstyle:NestedTryDepth\")\n    @Override\n    public boolean isHeld() {\n      try {\n        return pool.run(\n            conn -> {\n              try (PreparedStatement sql = conn.prepareStatement(GET_LOCK_SQL)) {\n                sql.setString(1, type.key);\n                sql.setString(2, lockId);\n                try (ResultSet rs = sql.executeQuery()) {\n                  return rs.next();\n                }\n              }\n            });\n      } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n        throw new UncheckedInterruptedException(e, \"Interrupted during isHeld\");\n      } catch (SQLException e) {\n        // SQL exception happened when getting lock information\n        throw new UncheckedSQLException(e, \"Failed to check the state of the lock %s\", this);\n      }\n    }\n\n    @SuppressWarnings(\"checkstyle:NestedTryDepth\")\n    @Override\n    public void unlock() {\n      try {\n        // Possible concurrency issue:\n        // - `unlock` and `tryLock` happens at the same time when there is an existing lock\n        //\n        // Steps:\n        // 1. `unlock` removes the lock in the database, but there is a temporary connection failure\n        // 2. `lock` finds that there is no lock, so creates a new lock\n        // 3. `unlock` retries the lock removal and removes the new lock\n        //","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java#L209-L245","documentation":"JdbcLock.isHeld runs a SELECT through the connection pool to check the lock row's instance ID. If the thread is interrupted during that query, the interrupt flag is restored and UncheckedInterruptedException('Interrupted during isHeld') is thrown; SQLException instead becomes 'Failed to check the state of the lock'.","triggerScenarios":"isHeld (invoked during tryLock's failure-recovery path or by the trigger loop) interrupted mid-SELECT — job cancel/failover while querying the lock table.","commonSituations":"Cancellation during lock-state verification; slow SELECTs on a contended DB widening the interruption window.","solutions":["If part of intentional cancellation, ignore and shut down cleanly.","If unexpected, find the interrupting component (cancel command, watchdog) and align shutdown ordering.","Reduce lock-table query latency (indexes, DB load) so isHeld completes fast.","Restart the trigger job to re-attempt lock acquisition."],"exampleFix":"// no code fix; operational: ensure graceful shutdown stops the trigger loop before cancelling tasks","handlingStrategy":"try-catch","validationCode":"// avoid calling isHeld on an interrupted thread\nif (Thread.currentThread().isInterrupted()) {\n    throw new IllegalStateException(\"Thread already interrupted\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    held = lock.isHeld();\n} catch (UncheckedInterruptedException e) {\n    Thread.currentThread().interrupt();\n    throw e; // propagate as cancellation\n}","preventionTips":["Stop the trigger loop gracefully before cancelling tasks","Keep lock-table queries fast (proper indexes, low DB load)","Avoid long blocking operations sharing the trigger thread","Always restore the interrupt flag when catching InterruptedException"],"tags":["jdbc","flink","interrupted","lock","cancellation"],"backgroundTag":"thread-interrupted","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}