Skip to content

[CORE-15249] sr/json: Optimise is_superset to increase recursion depth#29290

Merged
BenPope merged 11 commits into
redpanda-data:devfrom
BenPope:CORE-15249/sr/json_recursion_depth_2
Jan 19, 2026
Merged

[CORE-15249] sr/json: Optimise is_superset to increase recursion depth#29290
BenPope merged 11 commits into
redpanda-data:devfrom
BenPope:CORE-15249/sr/json_recursion_depth_2

Conversation

@BenPope

@BenPope BenPope commented Jan 16, 2026

Copy link
Copy Markdown
Contributor

Optimise compatibility checking for json to allow more nested schemas.

The depth was tuned by adding these options to the compiler to determine the stack frame sizes:

--copt=-fstack-usage --copt=-Wframe-larger-than=512 --copt=-Wno-error=frame-larger-than

Backports Required

  • none - not a bug fix
  • none - this is a backport
  • none - issue does not exist in previous branches
  • none - papercut/not impactful enough to backport
  • v25.3.x
  • v25.2.x
  • v25.1.x

Release Notes

Improvements

  • Schema Registry: Optimise compatibility checking for json to allow more nested schemas.

@BenPope BenPope requested review from IoannisRP and pgellert January 16, 2026 13:06
@BenPope BenPope self-assigned this Jan 16, 2026
Copilot AI review requested due to automatic review settings January 16, 2026 13:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes JSON schema compatibility checking to support deeper schema nesting by reducing recursion depth and improving the efficiency of type checking operations. The primary changes replace recursive function calls with iterative approaches and optimize data structures used in the type comparison logic.

Changes:

  • Introduced iterative schema traversal to prevent stack overflow on deeply nested schemas
  • Replaced type list with bitset-based operations for more efficient type comparisons
  • Refactored helper functions to reduce stack frame overhead during formatting operations

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/v/pandaproxy/schema_registry/json.cc Converted recursive schema collection to iterative approach, replaced type list operations with bitset operations, optimized formatting helpers
src/v/pandaproxy/schema_registry/test/test_json_schema.cc Added test for deeply nested schemas to validate stack overflow prevention

throw as_exception(invalid_schema(
fmt::format("{} has more than one combinator", pj{v})));
throw_invalid_schema(
"schema_invalid",

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first argument "schema_invalid" should not be passed to throw_invalid_schema. Based on the function signature at lines 73-75, throw_invalid_schema takes a format string and arguments, but the format string here is "{} has more than one combinator" (second argument). The extra "schema_invalid" string will cause a format string mismatch. This differs from the pattern used elsewhere where throw_invalid_schema is called with only the format string and arguments.

Suggested change
"schema_invalid",

Copilot uses AI. Check for mistakes.

@IoannisRP IoannisRP left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥🔥🔥🔥🔥

BenPope and claude committed...

Excellent way to shift blame if things break 😆

Really nice PR! a couple of minor comments

// Setting the limit to 66 causes corruption of the heap stack due to stack
// overflow.
constexpr int max_test_depth = 31;
constexpr int max_test_depth = 65;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chore:

you say 100 to commit message. Also in the messages of the previous commit it mentions much bigger depths.

For future clarity, i say just move this PR first in the commit history and increase depth to something unreasonable (like 1000), to make clear that this is just for testing purposes and it will be undone.

Instead of changing it in every PR, you can just document new limit in the comment... and then at the end, set it to whatever is needed. The limit is kinda dependent on platform, anyways.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chore:

you say 100 to commit message. Also in the messages of the previous commit it mentions much bigger depths.

I shouldn't have reordered commits! Fix incoming

For future clarity, i say just move this PR first in the commit history and increase depth to something unreasonable (like 1000), to make clear that this is just for testing purposes and it will be undone.

Instead of changing it in every PR, you can just document new limit in the comment... and then at the end, set it to whatever is needed. The limit is kinda dependent on platform, anyways.

The problem is that we never really know what the max is, the heap corruption may appear at shutdown several depths higher.

// Setting the limit to 84 causes corruption of the heap stack due to stack
// overflow.
constexpr int max_test_depth = 83;
constexpr int max_test_depth = 96;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

comment was not updated

namespace {

// Helper to create schema errors without inlining fmt::format machinery
// into the caller's stack frame. Marked cold since errors are exceptional.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marked cold since errors are exceptional

Is there something in the code that actually marks them as cold? 🤔
I was expecting to see a noinline or something like that

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marked cold since errors are exceptional

Is there something in the code that actually marks them as cold? 🤔 I was expecting to see a noinline or something like that

I removed them, it made no difference.

@IoannisRP

Copy link
Copy Markdown
Contributor

I think it would also be useful to add before/after stack frame sizes on the cover (once you are ready to commit, as they might still change will working through it)

@vbotbuildovich

vbotbuildovich commented Jan 16, 2026

Copy link
Copy Markdown
Collaborator

CI test results

test results on build#79153
test_class test_method test_arguments test_kind job_url test_status passed reason test_history
MountUnmountIcebergTest test_simple_remount {"cloud_storage_type": 1} integration https://buildkite.com/redpanda/redpanda/builds/79153#019bc6fb-2351-4aff-b1d5-aa1528ca5944 FLAKY 8/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.1833, p0=0.5718, reject_threshold=0.0100. adj_baseline=0.4553, p1=0.0938, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=MountUnmountIcebergTest&test_method=test_simple_remount
src/v/pandaproxy/schema_registry/test/test_json_schema src/v/pandaproxy/schema_registry/test/test_json_schema unit https://buildkite.com/redpanda/redpanda/builds/79153#019bc6eb-024a-4f12-a374-c2f601f5c015 FAIL 0/1
test results on build#79165
test_class test_method test_arguments test_kind job_url test_status passed reason test_history
MountUnmountIcebergTest test_simple_remount {"cloud_storage_type": 1} integration https://buildkite.com/redpanda/redpanda/builds/79165#019bc76d-b8a4-404c-b19f-c91e1742916b FLAKY 9/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.1830, p0=0.8675, reject_threshold=0.0100. adj_baseline=0.4547, p1=0.0217, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=MountUnmountIcebergTest&test_method=test_simple_remount
NodesDecommissioningTest test_decommission_status null integration https://buildkite.com/redpanda/redpanda/builds/79165#019bc767-d5aa-455a-ba9d-5df569322a36 FLAKY 10/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.0372, p0=1.0000, reject_threshold=0.0100. adj_baseline=0.1076, p1=0.3202, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=NodesDecommissioningTest&test_method=test_decommission_status
test results on build#79186
test_class test_method test_arguments test_kind job_url test_status passed reason test_history
WriteCachingFailureInjectionE2ETest test_crash_all {"use_transactions": false} integration https://buildkite.com/redpanda/redpanda/builds/79186#019bc7e9-1a03-46e7-805e-bf63485ae56b FLAKY 8/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.1060, p0=0.2873, reject_threshold=0.0100. adj_baseline=0.2856, p1=0.4222, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=WriteCachingFailureInjectionE2ETest&test_method=test_crash_all
TxAtomicProduceConsumeTest test_basic_tx_consumer_transform_produce {"with_failures": true} integration https://buildkite.com/redpanda/redpanda/builds/79186#019bc7e9-19ff-4176-9834-2c4bd5923a51 FLAKY 10/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.0041, p0=1.0000, reject_threshold=0.0100. adj_baseline=0.1000, p1=0.3487, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=TxAtomicProduceConsumeTest&test_method=test_basic_tx_consumer_transform_produce
test results on build#79249
test_class test_method test_arguments test_kind job_url test_status passed reason test_history
ControllerForcedReconfiguration_Size5 test_cluster_recovery {"scenario": "Simple"} integration https://buildkite.com/redpanda/redpanda/builds/79249#019bd639-9dcf-4560-b184-b19fc795e8f4 FLAKY 10/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.0315, p0=1.0000, reject_threshold=0.0100. adj_baseline=0.1000, p1=0.3487, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=ControllerForcedReconfiguration_Size5&test_method=test_cluster_recovery
DatalakeCustomPartitioningTest test_sticky_default {"catalog_type": "rest_jdbc", "cloud_storage_type": 1} integration https://buildkite.com/redpanda/redpanda/builds/79249#019bd639-9dcf-4560-b184-b19fc795e8f4 FLAKY 10/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.0000, p0=1.0000, reject_threshold=0.0100. adj_baseline=0.1000, p1=0.3487, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=DatalakeCustomPartitioningTest&test_method=test_sticky_default
NodesDecommissioningTest test_decommission_status null integration https://buildkite.com/redpanda/redpanda/builds/79249#019bd63e-9ad2-4301-9e51-7d0d51f0dc02 FLAKY 19/21 Test PASSES after retries.No significant increase in flaky rate(baseline=0.0387, p0=0.5462, reject_threshold=0.0100. adj_baseline=0.1118, p1=0.3287, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=NodesDecommissioningTest&test_method=test_decommission_status
RedpandaNodeOperationsSmokeTest test_node_ops_smoke_test {"cloud_storage_type": 1, "mixed_versions": false} integration https://buildkite.com/redpanda/redpanda/builds/79249#019bd63e-9ada-4e8c-800f-a930b9c5d2c5 FAIL 0/1 https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=RedpandaNodeOperationsSmokeTest&test_method=test_node_ops_smoke_test
SimpleEndToEndTest test_relaxed_acks {"write_caching": false} integration https://buildkite.com/redpanda/redpanda/builds/79249#019bd63e-9adc-4d39-8934-ad18f786f7ff FLAKY 10/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.0134, p0=1.0000, reject_threshold=0.0100. adj_baseline=0.1000, p1=0.3487, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=SimpleEndToEndTest&test_method=test_relaxed_acks

@michael-redpanda michael-redpanda left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dang this looks cool

jsoncons::jsonpointer::json_pointer this_obj_ptr,
jsoncons::ojson& this_obj,
json_schema_dialect dialect) {
std::vector<collect_work_item>& work_stack,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't we run into a oversized alloc issue here using a std::vector?

Of note: I've found that Claude really needs to be reminded about which containers to use

jsoncons::jsonpointer::json_pointer obj_ptr,
jsoncons::ojson& obj,
json_schema_dialect dialect) {
std::vector<collect_work_item> work_stack;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same issue here

@BenPope BenPope force-pushed the CORE-15249/sr/json_recursion_depth_2 branch from 0b93042 to 8eb84fd Compare January 16, 2026 15:11
@BenPope

BenPope commented Jan 16, 2026

Copy link
Copy Markdown
Contributor Author

Changes in force-push

  • Address review comments
  • Don't move from a const&
  • Add cycle detection
  • Increase max_recursion_depth

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment on lines 364 to 365
static constexpr int max_recursion_depth{200};
int _ref_units{max_recursion_depth};

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The max_recursion_depth has been increased from 8 to 200, but this constant is now misleading since the main recursion prevention mechanism is the cycle detection via visited set. Consider renaming this constant to better reflect its purpose (e.g., max_ref_resolution_depth) or documenting why this specific limit remains necessary alongside cycle detection.

Suggested change
static constexpr int max_recursion_depth{200};
int _ref_units{max_recursion_depth};
// Safety cap on the depth/amount of $ref resolution. Cycle detection via
// the visited set is the primary recursion guard; this remains as a
// secondary limit to prevent pathological inputs from consuming
// unbounded resources.
static constexpr int max_ref_resolution_depth{200};
int _ref_units{max_ref_resolution_depth};

Copilot uses AI. Check for mistakes.
};
// enough inlined space to hold all the values of json_type
using json_type_list = absl::InlinedVector<json_type, 7>;
using json_type_list = enum_bitset<json_type, 7>;

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The size parameter 7 is a magic number that should be replaced with a constant or derived from the enum. Consider using static_cast<std::size_t>(json_type::null) + 1 or defining a json_type_count constant to make the relationship between the enum and bitset size explicit.

Copilot uses AI. Check for mistakes.
jsoncons::uri base_uri,
jsoncons::jsonpointer::json_pointer obj_ptr,
jsoncons::ojson& obj,
json_schema_dialect dialect) {

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable is named work_stack but uses a chunked_vector. Consider renaming to work_queue or work_list since vectors don't necessarily convey LIFO semantics, or add a comment explaining why a vector is used for stack operations.

Suggested change
json_schema_dialect dialect) {
json_schema_dialect dialect) {
// Use chunked_vector as an explicit LIFO stack (push_back/back/pop_back)
// to avoid recursion on deeply nested schemas.

Copilot uses AI. Check for mistakes.

@pgellert pgellert left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great stuff! Can you please add the commands that you used for deriving the stack sizes / warning to the PR cover letter for future reference?

Comment thread src/v/pandaproxy/schema_registry/json.cc Outdated
Comment on lines +311 to +316
// Not implemented - only needed for input streams
char Peek() const { return 0; }
char Take() { return 0; }
size_t Tell() const { return 0; }
char* PutBegin() { return nullptr; }
size_t PutEnd(char*) { return 0; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these throw unimplemented / assert unreachable?

@pgellert pgellert Jan 19, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump on this. Mainly to:

  1. Confirm these are not accidentally used now
  2. Ensure they are not accidentally used in the future
  3. Show that they are unused if we need to trace down bugs in the future in this area

Comment thread src/v/pandaproxy/schema_registry/test/test_json_schema.cc Outdated
Comment thread src/v/pandaproxy/schema_registry/json.cc Outdated
BenPope and others added 6 commits January 16, 2026 16:14
Add a parameterized test that validates stack frame size optimizations
by testing compatibility checking on deeply nested JSON schemas. The test
creates schemas with nested object properties and measures the maximum
depth achievable before stack overflow.

Current baseline with optimizations: depth 70 (with jsoncons validation
disabled and max_recursion_depth=100).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Temporarily disable jsoncons metaschema validation and increase
max_recursion_depth to enable stack depth testing. This allows the
test_object_recursion_depths test to measure the actual stack limits
of the is_superset code path without being limited by jsoncons.

TODO: Re-enable validation once stack optimizations are complete.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Stack frame size changes:
- ::(anonymous namespace)::is_superset: 1464 -> 1368 (-96 bytes)

Signed-off-by: Ben Pope <ben@redpanda.com>
Two improvements from passing std::filesystem::path by const reference:

is_superset: 1368 → 1080 (-288 bytes)
is_object_properties_superset: 712 → 648 (-64 bytes)

Signed-off-by: Ben Pope <ben@redpanda.com>
This allows processing deeply nested schemas without stack overflow.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…_value_superset

Pass json_incompatibility_type and path separately instead of
pre-constructed json_incompatibility objects. The path is only
appended with prop_name when an error actually occurs, avoiding
temporary filesystem::path construction in the caller's stack frame.

Stack frame size changes:
- is_numeric_superset: 1032 -> 680 (-352 bytes)
- is_array_superset: 856 -> 616 (-240 bytes)
- is_object_superset: 1032 -> 792 (-240 bytes)
- is_string_superset: 664 -> <512 (no longer triggers warning)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@BenPope BenPope force-pushed the CORE-15249/sr/json_recursion_depth_2 branch from 8eb84fd to 82ed17a Compare January 16, 2026 17:28
@BenPope

BenPope commented Jan 16, 2026

Copy link
Copy Markdown
Contributor Author

Changes in force-push

  • Don't pass compatibility_context by reference into is_superset.
  • Tweak some limits

@BenPope BenPope requested a review from pgellert January 16, 2026 17:32

@IoannisRP IoannisRP left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only concern is that I don't see any tests for

sr/json: Add cycle detection

Do we have any existing tests that cover this?

Comment on lines +63 to +75
template<typename... Args>
error_info
make_invalid_schema(fmt::format_string<Args...> fmt, Args&&... args) {
return error_info{
error_code::schema_invalid,
fmt::format(fmt, std::forward<Args>(args)...)};
}

template<typename... Args>
[[noreturn]] void
throw_invalid_schema(fmt::format_string<Args...> fmt, Args&&... args) {
throw as_exception(make_invalid_schema(fmt, std::forward<Args>(args)...));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:
maybe add a noinline attribute on these for future-proofing the not-inlined behavior

Suggested change
template<typename... Args>
error_info
make_invalid_schema(fmt::format_string<Args...> fmt, Args&&... args) {
return error_info{
error_code::schema_invalid,
fmt::format(fmt, std::forward<Args>(args)...)};
}
template<typename... Args>
[[noreturn]] void
throw_invalid_schema(fmt::format_string<Args...> fmt, Args&&... args) {
throw as_exception(make_invalid_schema(fmt, std::forward<Args>(args)...));
}
template<typename... Args>
[[clang::noinline]] error_info
make_invalid_schema(fmt::format_string<Args...> fmt, Args&&... args) {
return error_info{
error_code::schema_invalid,
fmt::format(fmt, std::forward<Args>(args)...)};
}
template<typename... Args>
[[noreturn]][[clang::noinline]] void
throw_invalid_schema(fmt::format_string<Args...> fmt, Args&&... args) {
throw as_exception(make_invalid_schema(fmt, std::forward<Args>(args)...));
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not obvious that the noinline helps - I'm sure I tested with and without, and there was no difference.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the only reason for these functions to help is for them to not be inlined, right?

If so, the tag indeed would not "help". But what is inlined might change as we change compiler versions. Adding the tag makes it explicit and documents the desired behavior.

// overflow, which manifests as a crash during Seastar shutdown.
constexpr int max_test_depth = 129;
// Note: jsoncons validation overflows the stack at about 31.
// With validation disabled, setting the limit above ~139 causes corruption

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

130 became 139 in comment. Was this on purpose?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

130 became 139 in comment. Was this on purpose?

No

@BenPope

BenPope commented Jan 19, 2026

Copy link
Copy Markdown
Contributor Author

My only concern is that I don't see any tests for

sr/json: Add cycle detection

Do we have any existing tests that cover this?

The commit changes a test for cycles to now succeed rather than fail, and adds a comment along those lines.

pgellert
pgellert previously approved these changes Jan 19, 2026
Comment on lines +62 to +66
// Helper to create schema errors without inlining fmt::format machinery
// into the caller's stack frame.
template<typename... Args>
error_info
make_invalid_schema(fmt::format_string<Args...> fmt, Args&&... args) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need a [[noinline]]? Otherwise, I'd guess whether this + fmt::format gets inlined only depends on how aggressively the compiler is trying to optimize.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried with and without and there was no change to the frame size

Comment on lines +311 to +316
// Not implemented - only needed for input streams
char Peek() const { return 0; }
char Take() { return 0; }
size_t Tell() const { return 0; }
char* PutBegin() { return nullptr; }
size_t PutEnd(char*) { return 0; }

@pgellert pgellert Jan 19, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump on this. Mainly to:

  1. Confirm these are not accidentally used now
  2. Ensure they are not accidentally used in the future
  3. Show that they are unused if we need to trace down bugs in the future in this area

BenPope and others added 5 commits January 19, 2026 12:15
Add throw_as_exception helper to move fmt::format machinery out of
callers' stack frames. Replace pj/pjp ostream formatters with
format_to() methods that write directly to fmt::iterator.

Stack frame size changes:
- get_schema: 712 -> 600 (-112 bytes)
- is_numeric_superset: 712 -> 680 (-32 bytes)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This is the limit before a test fails.

Signed-off-by: Ben Pope <ben@redpanda.com>
Signed-off-by: Ben Pope <ben@redpanda.com>
Signed-off-by: Ben Pope <ben@redpanda.com>
Track visited (older, newer) schema pairs for cycle detection.
If we encounter the same pair twice during traversal, we've found a cycle
and can return early (compatible by assumption - cycles that differ would
have been caught on first visit).

Signed-off-by: Ben Pope <ben@redpanda.com>
@BenPope BenPope force-pushed the CORE-15249/sr/json_recursion_depth_2 branch from 82ed17a to 86c01d6 Compare January 19, 2026 12:16
@BenPope BenPope requested review from IoannisRP and pgellert January 19, 2026 12:16
@vbotbuildovich

Copy link
Copy Markdown
Collaborator

Retry command for Build#79249

please wait until all jobs are finished before running the slash command

/ci-repeat 1
skip-redpanda-build
skip-units
skip-rebase
tests/rptest/tests/random_node_operations_smoke_test.py::RedpandaNodeOperationsSmokeTest.test_node_ops_smoke_test@{"cloud_storage_type":1,"mixed_versions":false}

@BenPope

BenPope commented Jan 19, 2026

Copy link
Copy Markdown
Contributor Author

/ci-repeat 1
skip-redpanda-build
skip-units
skip-rebase
tests/rptest/tests/random_node_operations_smoke_test.py::RedpandaNodeOperationsSmokeTest.test_node_ops_smoke_test@{"cloud_storage_type":1,"mixed_versions":false}

@BenPope BenPope merged commit 9065eef into redpanda-data:dev Jan 19, 2026
19 checks passed
@vbotbuildovich

Copy link
Copy Markdown
Collaborator

/backport v25.3.x

@vbotbuildovich

Copy link
Copy Markdown
Collaborator

Failed to create a backport PR to v25.3.x branch. I tried:

git remote add upstream https://github.com/redpanda-data/redpanda.git
git fetch --all
git checkout -b backport-pr-29290-v25.3.x-892 remotes/upstream/v25.3.x
git cherry-pick -x 01b3cdc3d8 4012cdf270 8d40d84264 4c89a3c65b 3fb5a8010e 5d96e842b1 219f6c8c96 542ef24a70 543b1f422e fb6e585765 86c01d610d

Workflow run logs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants