{"record":{"id":"62ff42ef08fadbf8","repo":"apache/cassandra","slug":"command-command-took-too-long-exectime-ms","errorCode":null,"errorMessage":"Command '${command}' took too long (${execTime}ms >= ${quota}ms).","messagePattern":"Command '(.+?)' took too long \\((.+?)ms >= (.+?)ms\\)\\.","errorType":"exception","errorClass":"TimeQuotaExceededException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/index/sasi/plan/QueryController.java","lineNumber":172,"sourceCode":"\n        for (Map.Entry<Expression, Set<SSTableIndex>> e : view)\n        {\n            RangeIterator<Long, Token> index = TermIterator.build(e.getKey(), e.getValue());\n\n            builder.add(index);\n            perIndexUnions.add(index);\n        }\n\n        resources.put(expressions, perIndexUnions);\n        return builder;\n    }\n\n    public void checkpoint()\n    {\n\tlong executionTime = (nanoTime() - executionStart);\n\n        if (executionTime >= executionQuota)\n            throw new TimeQuotaExceededException(\n\t            \"Command '\" + command + \"' took too long \" +\n                \"(\" + TimeUnit.NANOSECONDS.toMillis(executionTime) +\n                \" >= \" + TimeUnit.NANOSECONDS.toMillis(executionQuota) + \"ms).\");\n    }\n\n    public void releaseIndexes(Operation operation)\n    {\n        if (operation.expressions != null)\n            releaseIndexes(resources.remove(operation.expressions.values()));\n    }\n\n    private void releaseIndexes(List<RangeIterator<Long, Token>> indexes)\n    {\n        if (indexes == null)\n            return;\n\n        indexes.forEach(FileUtils::closeQuietly);\n    }","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/index/sasi/plan/QueryController.java#L154-L190","documentation":"QueryController.checkpoint() enforces a per-query time quota for SASI query execution. Each time getPartition() (and other checkpoint call sites) runs, it compares elapsed nanos against executionQuota and throws TimeQuotaExceededException once the query has run longer than allowed, preventing long-running index scans from monopolizing coordinator resources.","triggerScenarios":"A SASI SELECT with many expressions or a broad term match (low selectivity, e.g. a range or prefix that hits millions of partitions) that takes longer than the quota (derived from the read timeout / cross_node_timeout settings) before checkpoint() is called from getPartition().","commonSituations":"Production queries with non-selective SASI predicates hitting huge partitions; quotas configured too low on busy clusters; queries that were fine before a data-size increase now exceed the execution window.","solutions":["Rewrite the query with more selective predicates (tighter ranges, additional EQ terms) so fewer partitions are scanned","Raise the quota indirectly by increasing the read timeouts it derives from (read_request_timeout_in_ms, range_request_timeout_in_ms) in cassandra.yaml","Ensure SASI indexes exist on the columns used so the planner narrows results before row evaluation","Use paging (LIMIT with paging state) and avoid unbounded broad scans in application code"],"exampleFix":"// before\nSELECT * FROM ks.logs WHERE message LIKE '%error%'; // scans whole index, exceeds quota\n// after\nSELECT * FROM ks.logs WHERE app = 'billing' AND day = '2026-09-09' AND message LIKE 'error%'; // selective EQ terms first","handlingStrategy":"try-catch","validationCode":"// Check selectivity before issuing: count matching rows with a bounded query first\ncqlsh> SELECT COUNT(*) FROM ks.logs WHERE app='billing' AND day='2026-09-09' LIMIT 100000;","typeGuard":null,"tryCatchPattern":"try {\n    ResultSet rs = session.execute(sasiQuery);\n} catch (TimeQuotaExceededException e) {\n    // narrow the predicates or split the query into smaller time-bounded slices\n    retryWithNarrowerBounds(e);\n}","preventionTips":["Always include at least one highly selective EQ term in SASI queries","Page through large result sets instead of issuing unbounded scans","Tune read timeouts deliberately; do not set them below realistic index-scan durations","Monitor for queries approaching the quota and alert before they time out"],"tags":["sasi","timeout","query-quota","performance"],"backgroundTag":"request-timeout","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}