Skip to content

Conversation

@JasonZhang517
Copy link
Contributor

Corresponding to #978
Based on existing create method:
static std::optional<std::shared_ptr> Create(
const std::string& local_hostname,
const std::string& metadata_connstring, const std::string& protocol,
const std::optionalstd::string& device_names = std::nullopt,
const std::string& master_server_entry = kDefaultMasterAddress,
const std::shared_ptr& transfer_engine = nullptr);

Added builder functions with std::move to reduce copy.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @JasonZhang517, 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 introduces a C++ builder pattern for the mooncake::Client class, enhancing the client creation process by offering a more structured, readable, and flexible API. The new MooncakeStoreBuilder allows for step-by-step configuration of client parameters, including validation for required fields, and optimizes string handling by leveraging std::move. This change aims to improve the maintainability and usability of client instantiation, moving away from a single, potentially complex Create method.

Highlights

  • New Builder Pattern: Introduced a MooncakeStoreBuilder class to provide a fluent, type-safe, and more readable way to configure and create mooncake::Client instances.
  • Parameter Handling: The builder methods (WithLocalHostname, WithMetadataConnectionString, etc.) utilize std::move for string parameters to reduce unnecessary copies during client configuration.
  • Required Field Validation: The Build() method within MooncakeStoreBuilder now includes validation to ensure essential parameters like local_hostname and metadata_connstring are provided before attempting to create a Client.
  • Deprecation Notice: The existing PyClient::setup method has been marked as deprecated, encouraging future use of the new MooncakeStoreBuilder for client initialization.
  • Internal Refactoring: The internal PyClient::setup_internal method has been updated to use the new MooncakeStoreBuilder for constructing Client objects, demonstrating its intended usage.
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
Contributor

@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 introduces a MooncakeStoreBuilder to provide a fluent and readable API for constructing mooncake::Client instances. This is a great improvement over the static Create method with many parameters. The implementation is solid, and it's correctly used to refactor PyClient::setup_internal.

My review includes a few suggestions to further enhance the new builder:

  • Making the Build() method const to improve API correctness.
  • Simplifying the usage of the builder in pybind_client.cpp to a single fluent chain.
  • A minor refinement in the Build() method's error message construction for better performance and C++ idiomaticity.

Overall, this is a well-executed enhancement.

MooncakeStoreBuilder& WithExistingTransferEngine(
std::shared_ptr<TransferEngine> transfer_engine);

[[nodiscard]] std::optional<std::shared_ptr<Client>> Build();
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The Build() method does not modify the state of the MooncakeStoreBuilder. It's good practice to mark such methods as const. This improves API correctness by clearly stating the method's intent and allows it to be called on const builder instances. You'll also need to update the implementation in client.cpp.

Suggested change
[[nodiscard]] std::optional<std::shared_ptr<Client>> Build();
[[nodiscard]] std::optional<std::shared_ptr<Client>> Build() const;

return *this;
}

std::optional<std::shared_ptr<Client>> MooncakeStoreBuilder::Build() {
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

To match the const qualifier added to the declaration in the header file, the implementation of Build() should also be marked as const.

Suggested change
std::optional<std::shared_ptr<Client>> MooncakeStoreBuilder::Build() {
std::optional<std::shared_ptr<Client>> MooncakeStoreBuilder::Build() const {

Comment on lines 462 to 467
for (size_t i = 0; i < missing.size(); ++i) {
if (i != 0) {
joined.append(", ");
}
joined.append(missing[i]);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This loop for joining strings with a separator can be made slightly more efficient and idiomatic by handling the first element outside the loop. This avoids the conditional check if (i != 0) in every iteration.

        joined.append(missing[0]);
        for (size_t i = 1; i < missing.size(); ++i) {
            joined.append(", ");
            joined.append(missing[i]);
        }

Comment on lines 181 to 194
MooncakeStoreBuilder builder;
builder.WithLocalHostname(this->local_hostname)
.WithMetadataConnectionString(metadata_server)
.UsingProtocol(protocol)
.WithMasterServerEntry(master_server_addr);

if (device_name) {
builder.WithRdmaDeviceNames(*device_name);
}
if (transfer_engine) {
builder.WithExistingTransferEngine(transfer_engine);
}

auto client_opt = builder.Build();
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The builder pattern is most powerful when its methods are chained fluently. The current implementation can be simplified into a single, more readable statement. The if conditions for optional parameters can be avoided by using std::optional::value_or for device_name and by passing the (potentially null) transfer_engine shared_ptr directly, as the builder handles these cases gracefully.

    auto client_opt = MooncakeStoreBuilder()
        .WithLocalHostname(this->local_hostname)
        .WithMetadataConnectionString(metadata_server)
        .UsingProtocol(protocol)
        .WithMasterServerEntry(master_server_addr)
        .WithRdmaDeviceNames(device_name.value_or(""))
        .WithExistingTransferEngine(transfer_engine)
        .Build();

@stmatengss
Copy link
Collaborator

Use clang-format to fix code format issue.

@stmatengss stmatengss requested a review from xiaguan November 4, 2025 09:54
Copy link
Collaborator

@xiaguan xiaguan left a comment

Choose a reason for hiding this comment

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

Add a simple unit test for the builder.

auto client_opt = mooncake::Client::Create(
this->local_hostname, metadata_server, protocol, device_name,
master_server_addr, transfer_engine);
MooncakeStoreBuilder builder;
Copy link
Collaborator

Choose a reason for hiding this comment

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

revert this? just use create is good enough i think

Copy link
Contributor

@nickyc975 nickyc975 left a comment

Choose a reason for hiding this comment

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

Hi, @JasonZhang517. Glad to see the improvement of client initializition! I have several naming suggestions on this PR.

@stmatengss stmatengss requested a review from nickyc975 November 13, 2025 15:58
* specify only the options they need while reusing existing Client::Create
* logic under the hood.
*/
class MooncakeStoreBuilder {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think ClientBuilder should be a better name in the context, as we are infact building a Client, not a MooncakeStore.

Copy link
Collaborator

Choose a reason for hiding this comment

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

How about MooncakeStoreClientBuilder? Don't be afraid of a long name.

Copy link
Contributor

@nickyc975 nickyc975 left a comment

Choose a reason for hiding this comment

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

Hi, @JasonZhang517. I have found several problems in the PR. Please take a look.


MooncakeStoreBuilder& MooncakeStoreBuilder::WithLocalHostname(
std::string local_hostname) {
local_hostname_ = std::move(local_hostname);
Copy link
Contributor

Choose a reason for hiding this comment

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

Use const std::string& instead of std::string for the parameter, and don't move the parameter. Please also update the other "WithXXX" methods that taking strings as arguments.

return *this;
}

tl::expected<std::shared_ptr<Client>, std::string> MooncakeStoreBuilder::Build()
Copy link
Contributor

Choose a reason for hiding this comment

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

Returning string for errors is not a good practice. String is not structured and hard to be programmatically processed. You can see the bad result in the unit tests that you must search the returned string to check whether it is expected.

I suggest to return an ErrorCode for failure. For example, INVALID_PARAMS for missing required field, INTERNAL_ERROR for client creation failure. And provide a GetMissingFields() method to get the missing fields if needed.


if (!missing.empty()) {
std::string joined;
joined.reserve(missing.size() * 16);
Copy link
Contributor

Choose a reason for hiding this comment

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

The reserve is not necessary because this is not a performance critical path and 16 is a magic number. It's fine to let the string allocate space as needed.

for (size_t i = 0; i < missing.size(); ++i) {
if (i != 0) {
joined.append(", ");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This for loop and the if (i != 0) is redundent and confusing, just remove them.

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.

4 participants