Skip to content

Conversation

@dranikpg
Copy link
Contributor

@dranikpg dranikpg commented Nov 29, 2025

Relevant to #6137

  1. Half of SmallStr code assumed values could be less than kPrefLen, half of it asserted it, parts would've just broke. I kept at DCHECK at assign and simplified all other parts
  2. For some reason, if the length of a new string is greater than the current small str, we just decided to pick a raw allocated (robj) string instead, even if it would fit into a reallocated small string
  3. Simplified CompactObj::GetString() part with encodings

Comment on lines -1591 to -1595
tl.small_str_bytes += u_.small_str.Assign(encoded);
return;
}

if (taglen_ == SMALL_TAG && encoded.size() <= u_.small_str.size()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this was the part with encoded.size() <= u_.small_str.size()

@dranikpg dranikpg requested a review from BorysTheDev December 1, 2025 17:58
@dranikpg dranikpg marked this pull request as ready for review December 1, 2025 17:58
BorysTheDev
BorysTheDev previously approved these changes Dec 2, 2025
Copy link
Contributor

@BorysTheDev BorysTheDev left a comment

Choose a reason for hiding this comment

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

I don't understand a lot, ask somebody else to review too

if (size_ == 0) {
// packed structs can not be tied here.
// If the allocation is large enough and space efficient, we can avoid allocating
if (s.size() >= size_ || s.size() * 2 < MallocUsed()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

something is wrong with this condition, imho

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, it's just the inverse of the comment, I'll update it

Copy link
Collaborator

Choose a reason for hiding this comment

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

but I think the condition is wrong.
size_ = 20, malloc_used = 28, s.size() = 24 - you reallocate because of the first part. unnecessary. basically you only need to compare with MallocUsed imho

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added a todo, I can do it now. The code previously didn't allow any strings longer at all to be assigned

Copy link
Contributor

Copilot AI left a comment

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 refactors the SmallString class to enforce a critical invariant that was previously inconsistently applied: SmallString should only be used for strings with length strictly greater than kPrefLen (10 bytes). The refactoring simplifies code by removing redundant checks, fixes an inefficiency where growing a SmallString would unnecessarily switch to ROBJ_TAG allocation, and consolidates encoding/decoding logic in CompactObj::GetString().

Key changes:

  • Enforced size > kPrefLen invariant throughout SmallString with a DCHECK in Assign() and removed all defensive size <= kPrefLen checks
  • Fixed EncodeString() to properly reuse SmallString allocation when growing, instead of falling back to ROBJ_TAG
  • Refactored GetString() to unify encoding logic for both ROBJ_TAG and SMALL_TAG cases

Reviewed changes

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

File Description
src/core/small_string.h Updated API: renamed GetV() to Get() with new overloads, changed size() return type to size_t, removed Reset() method, updated documentation to clarify usage for strings > 10 bytes
src/core/small_string.cc Simplified Assign() reallocation logic, streamlined Free()/MallocUsed()/Equal()/Get() methods by removing size <= kPrefLen checks, refactored Get() with new overloads, added CanAllocate check in DefragIfNeeded()
src/core/compact_object.cc Fixed EncodeString() to reuse SMALL_TAG when growing instead of switching to ROBJ_TAG, consolidated encoding/decoding logic in GetString() to handle both ROBJ_TAG and SMALL_TAG uniformly, removed kUseSmallStrings constant


if (size_ == 0) {
// packed structs can not be tied here.
// If the allocation is large enough and space efficient, we can avoid allocating
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

[nitpick] The comment placement is confusing. It describes when we avoid reallocating (the else branch), but is placed before the if statement. Consider moving it above line 69 (before the else block) or rephrasing to describe the if condition: "Reallocate if growing or if space-inefficient (new size < half of allocated space)"

Suggested change
// If the allocation is large enough and space efficient, we can avoid allocating
// Reallocate if growing or if space-inefficient (new size < half of allocated space)

Copilot uses AI. Check for mistakes.
@dranikpg
Copy link
Contributor Author

dranikpg commented Dec 8, 2025

I use mi_good_size now to check if we need to grow. This is a logical change in this PR

@dranikpg dranikpg merged commit c507fa4 into dragonflydb:main Dec 8, 2025
10 checks passed
@dranikpg dranikpg deleted the refactor-small-string branch December 8, 2025 14:48
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.

3 participants