Skip to content

Conversation

xiaguan
Copy link
Collaborator

@xiaguan xiaguan commented Oct 17, 2025

Problem

The deprecated Json::Reader class uses static global variables internally, causing race conditions and memory corruption in multi-threaded scenarios. This led to intermittent CI crashes with symptoms including:

  • Segmentation faults
  • Double free or corruption errors
  • JSON parse failures in concurrent tests

Solution

Replaced all Json::Reader usage with the thread-safe Json::CharReaderBuilder API across:

  • mooncake-transfer-engine: transfer_metadata_plugin, transfer_metadata, topology
  • mooncake-common: default_config

Testing

Verified the fix resolves the issue:

  • ConcurrentPutGetWithLeaseTimeOut test passes consistently (3/3 runs)
  • ✅ All basic tests pass without crashes
  • ✅ Thread-safe JSON parsing validated

This should eliminate the small probability CI crashes in concurrent scenarios.

…e CharReaderBuilder

The deprecated Json::Reader class uses static global variables internally,
causing race conditions and crashes in multi-threaded scenarios. This fix
replaces all Json::Reader usage with the thread-safe Json::CharReaderBuilder
API across the transfer engine and common modules.

Changes:
- mooncake-transfer-engine: Updated JSON parsing in transfer_metadata_plugin,
  transfer_metadata, and topology modules
- mooncake-common: Fixed JSON parsing in default_config
- All JSON parsing now uses CharReaderBuilder for thread safety

This resolves intermittent CI crashes in concurrent tests like
ConcurrentPutGetWithLeaseTimeOut.
@xiaguan xiaguan requested review from alogfans and doujiang24 and removed request for alogfans October 17, 2025 07:46
Copy link

Summary of Changes

Hello @xiaguan, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances system stability by systematically replacing the deprecated and thread-unsafe Json::Reader class with the modern, thread-safe Json::CharReaderBuilder across several core components. This critical update resolves intermittent CI crashes, memory corruption issues, and JSON parsing failures that occurred in multi-threaded environments, ensuring more reliable and robust JSON processing throughout the application.

Highlights

  • Problem Resolution: Addresses intermittent CI crashes, segmentation faults, double free errors, and JSON parse failures caused by the deprecated Json::Reader class, which used static global variables leading to race conditions in multi-threaded scenarios.
  • API Migration: Replaces all usages of the deprecated Json::Reader with the modern, thread-safe Json::CharReaderBuilder API for robust JSON parsing.
  • Scope of Change: The update impacts JSON parsing logic across mooncake-common (default config loading) and mooncake-transfer-engine (topology, transfer metadata, and various storage/handshake plugins).
  • Helper Function Introduction: A new static helper function, parseJsonString, has been introduced in transfer_metadata_plugin.cpp to centralize and standardize the new thread-safe JSON parsing logic.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request successfully replaces the deprecated and thread-unsafe Json::Reader with the modern Json::CharReaderBuilder across the codebase, addressing potential race conditions. The changes are well-executed, and the introduction of a parseJsonString helper function is a good pattern for centralizing the new parsing logic. I've added a few suggestions to further improve the code by enhancing error handling, removing redundant code, and optimizing a JSON conversion function for better performance and robustness.

Comment on lines 316 to 328
Json::Value root;
Json::Reader reader;
reader.parse(toString(), root);
std::string json_str = toString();

// Use thread-safe CharReaderBuilder instead of deprecated Reader
Json::CharReaderBuilder builder;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
std::string errs;

if (!reader->parse(json_str.data(), json_str.data() + json_str.size(),
&root, &errs)) {
LOG(ERROR) << "Topology::toJson: JSON parse error: " << errs;
}
return root;

Choose a reason for hiding this comment

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

medium

This implementation serializes the topology to a string via toString() and then immediately parses it back into a Json::Value. This is inefficient and creates a tight coupling with toString(), which could lead to issues like infinite recursion if toString() were to call toJson().

You can construct the Json::Value directly from the matrix_ member variable. This is more efficient and robust.

Suggested change
Json::Value root;
Json::Reader reader;
reader.parse(toString(), root);
std::string json_str = toString();
// Use thread-safe CharReaderBuilder instead of deprecated Reader
Json::CharReaderBuilder builder;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
std::string errs;
if (!reader->parse(json_str.data(), json_str.data() + json_str.size(),
&root, &errs)) {
LOG(ERROR) << "Topology::toJson: JSON parse error: " << errs;
}
return root;
Json::Value root;
for (const auto &pair : matrix_) {
root[pair.first] = pair.second.toJson();
}
return root;

@xiaguan
Copy link
Collaborator Author

xiaguan commented Oct 17, 2025

/gemini

Copy link

It looks like you tried to invoke a command, but you just typed /gemini. To use a command, please specify it after /gemini, for example, /gemini review or /gemini summary. You can also type /gemini help to see a list of available commands.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

@xiaguan
Copy link
Collaborator Author

xiaguan commented Oct 17, 2025

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request successfully replaces the deprecated and thread-unsafe Json::Reader with the modern Json::CharReaderBuilder API, addressing potential race conditions. The changes are well-implemented across multiple files. My review includes a few suggestions for improvement:

  • Refactoring an inefficient JSON serialization-then-deserialization pattern in one function.
  • Removing a redundant and potentially incorrect try-catch block.
  • Consistently applying parser configurations for minor performance gains and code uniformity.

Overall, this is a solid fix that improves the thread safety and robustness of JSON handling.

Comment on lines 71 to 72
try {
processNode(root, "");
} catch (const std::exception& e) {
file.close();
throw e;
}

Choose a reason for hiding this comment

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

high

This try-catch block is redundant and potentially incorrect. It catches an exception and immediately re-throws it, which provides no value. The caller of loadFromJSON can handle any exceptions from processNode directly.

Furthermore, throw e; re-throws the exception by value, which can lead to object slicing if the caught exception is a derived class of std::exception. The correct way to re-throw the original exception is with a bare throw;.

Given the redundancy, the best solution is to remove the try-catch block entirely.

    processNode(root, "");

// Helper function to parse JSON string using thread-safe CharReaderBuilder
static bool parseJsonString(const std::string &json_str, Json::Value &value,
std::string *error_msg = nullptr) {
Json::CharReaderBuilder builder;

Choose a reason for hiding this comment

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

medium

For consistency with other parts of the codebase (e.g., default_config.cpp) and for a minor performance improvement, it's good practice to explicitly disable comment collection when parsing JSON that is not expected to contain comments.

Suggested change
Json::CharReaderBuilder builder;
Json::CharReaderBuilder builder;
builder["collectComments"] = false;

}

// Use thread-safe CharReaderBuilder instead of deprecated Reader
Json::CharReaderBuilder builder;

Choose a reason for hiding this comment

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

medium

For consistency with other parts of the codebase (e.g., default_config.cpp) and for a minor performance improvement, it's good practice to explicitly disable comment collection when parsing JSON that is not expected to contain comments.

Suggested change
Json::CharReaderBuilder builder;
Json::CharReaderBuilder builder;
builder["collectComments"] = false;

Comment on lines 305 to 319
Json::Value root;
Json::Reader reader;
reader.parse(toString(), root);
std::string json_str = toString();

// Use thread-safe CharReaderBuilder instead of deprecated Reader
Json::CharReaderBuilder builder;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
std::string errs;

if (!reader->parse(json_str.data(), json_str.data() + json_str.size(),
&root, &errs)) {
LOG(ERROR) << "Topology::toJson: JSON parse error: " << errs;
}

Choose a reason for hiding this comment

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

medium

This function is inefficient as it calls toString() to serialize a Json::Value to a string, and then immediately parses that string back into a Json::Value. The toString() function itself builds the Json::Value that is needed. You can avoid the unnecessary serialization and parsing by directly constructing the Json::Value here, which is both more performant and easier to read.

Suggested change
Json::Value root;
Json::Reader reader;
reader.parse(toString(), root);
std::string json_str = toString();
// Use thread-safe CharReaderBuilder instead of deprecated Reader
Json::CharReaderBuilder builder;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
std::string errs;
if (!reader->parse(json_str.data(), json_str.data() + json_str.size(),
&root, &errs)) {
LOG(ERROR) << "Topology::toJson: JSON parse error: " << errs;
}
Json::Value root(Json::objectValue);
for (const auto& entry : matrix_) {
root[entry.first] = entry.second.toJson();
}

Instead of serializing to string and parsing back, directly construct
Json::Value from matrix_. This is more efficient and eliminates the
need for JSON parsing entirely in this method.
@xiaguan xiaguan force-pushed the fix-json-thread-safety branch from 1959d80 to 930acb6 Compare October 17, 2025 08:01
@xiaguan
Copy link
Collaborator Author

xiaguan commented Oct 17, 2025

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively addresses the thread-safety issue of Json::Reader by migrating to the Json::CharReaderBuilder API. The changes are applied consistently across the codebase, and the introduction of a helper function for parsing is a good practice. I have a few suggestions to further improve the implementation, mainly concerning error handling in file operations, removing redundant code, and ensuring consistent behavior in the new JSON parsing logic for better performance.

// Helper function to parse JSON string using thread-safe CharReaderBuilder
static bool parseJsonString(const std::string &json_str, Json::Value &value,
std::string *error_msg = nullptr) {
Json::CharReaderBuilder builder;

Choose a reason for hiding this comment

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

high

To maintain consistency with other parts of the codebase (like in default_config.cpp) and the previous Json::Reader behavior, and for better performance, it's recommended to explicitly disable comment collection in the Json::CharReaderBuilder. The default for CharReaderBuilder is to collect comments, which might be an unnecessary overhead when parsing JSON that doesn't contain comments.

Suggested change
Json::CharReaderBuilder builder;
Json::CharReaderBuilder builder;
builder["collectComments"] = false;

Copy link
Collaborator

@alogfans alogfans left a comment

Choose a reason for hiding this comment

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

LGTM. By the way, we will replace it with nlohmann/json in the next version (for cleanness.

@alogfans alogfans merged commit 14b0586 into kvcache-ai:main Oct 20, 2025
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants