Skip to content

Conversation

@phoebusm
Copy link
Collaborator

@phoebusm phoebusm commented Oct 30, 2025

Reference Issues/PRs

https://man312219.monday.com/boards/7852509418/pulses/18298965201

What does this implement or fix?

read

batch_read_keys read index keys of individual leaf nodes one by one during submission of read tasks. This PR has made this step runs in parallel in C++ layer.
It has shown read performance improvment, espceially on slow network or data with more leaf nodes:

Read Time(s)
Remote AWS Local S3 Storage (moto)
Before After Before After
200 Large Dataframe 98.4112 50.547 27.7294 25.2147
2000 Small Dataframe 159.712 9.73144 33.0835 10.7383
batch_read

It has been changed to unify to code path with read, Now node keys are read in the same chain of root keys.
The performance has not bettered or worsened, as expected.

Read Time(s)
Remote AWS Local S3 Storage (moto)
Before After Before After
2000 Symbols × 200 Dataframe 7.379 7.161 7.224 7.252

Any other comments?

ASV benchmark fails because of unreliable arrow and peakmem tests. They can be ignored.

Checklist

Checklist for code changes...
  • Have you updated the relevant docstrings, documentation and copyright notice?
  • Is this contribution tested against all ArcticDB's features?
  • Do all exceptions introduced raise appropriate error messages?
  • Are API changes highlighted in the PR description?
  • Is the PR labelled as enhancement or bug so it appears in autogenerated release notes?

@phoebusm phoebusm changed the title Feature/recursive normalizer optimization Improve recursive normalized data read performance Oct 31, 2025
@phoebusm phoebusm added the minor Feature change, should increase minor version label Oct 31, 2025
@phoebusm phoebusm marked this pull request as ready for review October 31, 2025 18:51
@phoebusm phoebusm marked this pull request as draft November 5, 2025 13:54
@phoebusm phoebusm force-pushed the feature/recursive_normalizer_optimization branch 3 times, most recently from 49d4f83 to 8d9256b Compare November 7, 2025 18:15
@phoebusm phoebusm force-pushed the feature/recursive_normalizer_optimization branch from 8d9256b to 785f385 Compare November 11, 2025 14:02
@phoebusm phoebusm force-pushed the feature/recursive_normalizer_optimization branch from a52e95d to 0b72b38 Compare November 12, 2025 16:10
@phoebusm phoebusm marked this pull request as ready for review November 12, 2025 20:05
@phoebusm phoebusm added patch Small change, should increase patch version and removed minor Feature change, should increase minor version labels Nov 12, 2025
manager.log_info()

def get_symbol_name(self, symbol_idx=0):
return f"nested_dict_{self.params[0]}_sym{symbol_idx}"
Copy link
Collaborator

Choose a reason for hiding this comment

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

self.params[0] is [1000], this doesn't make much sense?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the point was slightly missed. If we added another num_dict_entries parameter (e.g. so it's [1000, 2000], then we will want separate symbol names for the different number of dict entries

Copy link
Collaborator Author

@phoebusm phoebusm Nov 19, 2025

Choose a reason for hiding this comment

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

I have rewritten this bit to make it less ambiguous, as the data is not persisted anyway

Copy link
Collaborator

Choose a reason for hiding this comment

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

Are there already lmdb benchmarks for reading recursively normalized data?
What about for writing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yea why not LMDB.
I didn't touch write but yea it's worth adding the write asv test

Copy link
Collaborator

Choose a reason for hiding this comment

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

OK cool, can remove the real_ from this filename now then

@phoebusm phoebusm force-pushed the feature/recursive_normalizer_optimization branch from 6f9a6d3 to 407257a Compare November 19, 2025 13:03
}
}

inline ReadResult create_python_read_result(
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Just moving existing function to a new place to resolve some circular dependency issue

return versioned_item;
}

auto get_read_and_process_fn(
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@phoebusm phoebusm force-pushed the feature/recursive_normalizer_optimization branch from 407257a to a7c4926 Compare November 19, 2025 13:19
@phoebusm phoebusm force-pushed the feature/recursive_normalizer_optimization branch from bb9f7c4 to 8471058 Compare November 20, 2025 11:35
}
}

inline ReadResult create_python_read_result(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can this be moved to a .cpp file

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It has been marked inline explicitly so I prefer not to touch that

Comment on lines 37 to 44
py::list node_results;
for (auto& node_result : ret.node_results) {
node_results.append(py::make_tuple(
node_result.symbol_,
std::move(node_result.frame_data_),
python_util::pb_to_python(node_result.norm_meta_)
));
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This seems duplicated in python_utils.hpp can it be extracted in a function?

for (const auto& key : keys) {
node_futures.emplace_back(read_frame_for_version(store(), key, read_query, read_options, handler_data));
}
auto node_trys = folly::collectAll(node_futures).get();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since we're not wrapping exceptions as in batch data can't we use folly::collect to fail faster? In that case we must be very careful not to have segfaults on failures and make all parameters for the future shared_ptrs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Me and Alex have discussion regarding this and we think, as fail faster is not that important here, this implemetation is prefered

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

Labels

patch Small change, should increase patch version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants