Skip to content

fix(json_family): Fix json memory tracking issues. SECOND PR #5056

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

BagritsevichStepan
Copy link
Contributor

@BagritsevichStepan BagritsevichStepan commented May 5, 2025

fixes a lot of json memory tracking issues, #5055 , #5054 .
Also, partially fixes #4926

Bugs that were found and fixed:

  1. Memory tracking bug for the JSON.SET command: We didn't reset the result of ShardJsonFromString, which parses the json_str into the jsoncons's json and returns optional of this. The bug was that std::optional still holds the value even after std::move. So we overestimate the memory usage.
  2. Bug in memory tracker when we overestimate the memory usage because of this:
if (is_op_set) {
      diff += static_cast<int64_t>(mi_usable_size(pv.GetJson()));
}
  1. Bug in partial JSON.SET when we called ShardJsonFromString before starting the memory tracking
  2. Bug in JsonMutateOperation, where we called op_args.shard->search_indices()->RemoveDoc after starting the memory tracking. RemoveDoc has a static cache that may allocate some memory, but this memory does not belong to the JSON object itself. As a result, memory usage will be overestimated in this case.
  3. A lot of bugs in JSON.DEL command - we didn't update the indexes and track the memory usage at all. One of the bugs is good described in JSON value is not updated in the indexes after the JSON.DEL command #5055
  4. Bug in indexes for the JSON.SET command: JSON value is removed from the index after a failed JSON.SET command #5054

To fix this, I introduced json_family_memory_test and changed JsonMemTracker to JsonAutoUpdater, which eliminates most of the bugs described above.
It also ensures that RemoveDoc is called before memory tracking starts, and that AddDoc is called after SetJsonSize and also it will be called even if an error occurs.
Therefore, whenever we perform an update operation on a JSON value, this class must be used.

@BagritsevichStepan BagritsevichStepan self-assigned this May 5, 2025
@BagritsevichStepan BagritsevichStepan changed the title fix(json_family): Fix json memory tracking issues fix(json_family): Fix json memory tracking issues. SECOND PR May 5, 2025
@@ -2060,6 +2111,8 @@ void JsonFamily::Register(CommandRegistry* registry) {
*registry << CI{"JSON.ARRAPPEND", CO::WRITE | CO::DENYOOM | CO::FAST, -4, 1, 1, acl::JSON}.HFUNC(
ArrAppend);
*registry << CI{"JSON.ARRINDEX", CO::READONLY | CO::FAST, -4, 1, 1, acl::JSON}.HFUNC(ArrIndex);
*registry << CI{"JSON._MEMUSAGE", CO::READONLY | CO::FAST, 2, 1, 1, acl::JSON}.HFUNC(
Copy link
Collaborator

@romange romange May 5, 2025

Choose a reason for hiding this comment

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

you do not need it, we already have "memory usage " that should work for json as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As I understand, MEMORY USAGE also includes the size of the key, which might be an issue in this case. I think it would be useful to add a flag to the MEMORY USAGE command that excludes the key size from the calculation.

if (update_on_delete_ && !set_size_was_called_) {
SetJsonSize();
} else if (!set_size_was_called_) {
VLOG(1) << "JsonAutoUpdater destructor called without SetJsonSize() being called. This may "
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe LOG(DFATAL) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It shouldn't fail in debug. For example:

JsonAutoUpdater updater{};
...
if (<result is not valid>) {
   return;
}

If the result is not valid we will not update the json. This means we don't need to call SetJsonSize, and that's totally fine. I thought we could use LOG(WARNING) here.

@romange
Copy link
Collaborator

romange commented May 5, 2025

Really good work, @BagritsevichStepan !

@BagritsevichStepan
Copy link
Contributor Author

I have split this PR into 4 separate PRs:
#5068, #5069, #5070, #5075

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.

Memory tracking tests for JSON and STREAMs
2 participants