-
-
Notifications
You must be signed in to change notification settings - Fork 621
fix: sorting by string with OPTION scroll #3936
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
base: master
Are you sure you want to change the base?
Conversation
9bc456c to
d347ab2
Compare
There was a problem hiding this 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 fixes an issue with sorting by string attributes when using the OPTION scroll feature (issue #3928). The fix addresses how string attributes are handled in scroll sorters by properly mapping them to their internal STRINGPTR representations used for sorting.
- Adds proper handling for string attribute sorting with scroll tokens by mapping SPH_ATTR_STRING to SPH_ATTR_STRINGPTR
- Implements correct memory management for allocated string pointers with tracking and cleanup
- Fixes the
Reset()call to useGetDynamicSize()instead ofGetRowSize()to properly allocate only dynamic attributes
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| test/test_308/test.xml | Adds comprehensive test cases for string sorting with scroll (both ASC and DESC) using both SphinxQL and JSON API |
| test/test_308/model.bin | Updates expected test results to include brand_name field in outputs and validate string scroll behavior |
| test/test_307/model.bin | Fixes expected results for existing string sorting test - now correctly returns only rows after scroll position (1 instead of 5) |
| src/sorterscroll.cpp | Implements core fix: remaps string attributes to STRINGPTR for scroll comparison, adds pointer tracking, and fixes memory management |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
4a4bd4e to
f996bdd
Compare
Related issue #3928
f996bdd to
1dbef93
Compare
Notes after the fixProblemWhen using Root CauseString attributes in Manticore are internally remapped for sorting purposes:
The scroll sorter was not aware of this remapping, so when it tried to:
It would find Solution Approach1. Attribute Remapping LogicAdded remapping detection in two key places:
This ensures the scroll sorter works with the same internal representation that the sorting system uses. 2. Memory Management FixProblem: The original code tracked allocated string pointers by storing attribute info pointers, then later tried to retrieve the actual pointer values from Solution: Changed to store the actual
3. Memory Allocation FixChanged
Key Design Decisions
TestingThe fix was tested with:
|
glookka
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once again, it is difficult to evaluate if the changes are correct without checking out, building and running tests manually. All I see in that PR is that the model was changed in test_307. Why? What changed?
| if ( i.m_eType==SPH_ATTR_STRINGPTR && pAttr->m_eAttrType==SPH_ATTR_STRING ) | ||
| { | ||
| CSphString sRemappedName; | ||
| sRemappedName.SetSprintf ( "@int_attr_%s", i.m_sSortAttr.cstr() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's GetInternalAttrPrefix() for that.
| { | ||
| case SPH_ATTR_STRINGPTR: | ||
| sphSetRowAttr ( pRowData, pAttr->m_tLocator, (SphAttr_t)sphPackPtrAttr ( { (const BYTE*)i.m_sValue.cstr(), i.m_sValue.Length() } ) ); | ||
| // After remapping, pAttr should be SPH_ATTR_STRINGPTR, but check to be safe |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what asserts are for
src/sorterscroll.cpp
Outdated
| BYTE * pPacked = sphPackPtrAttr ( { (const BYTE*)i.m_sValue.cstr(), i.m_sValue.Length() } ); | ||
| sphSetRowAttr ( pRowData, pAttr->m_tLocator, (SphAttr_t)pPacked ); | ||
| // Track the allocated pointer value directly | ||
| m_dAllocatedPtrs.Add(pPacked); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the m_dAllocatedPtrs array? We have the sorter schema, we know which attrs were potentially allocated (sphIsDataPtrAttr()), so we can just loop through them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit 2, but it now leads to a crash. As discussed, it makes sense for you to look into this yourself.
Eliminated the m_dAllocatedPtrs vector and adjusted memory deallocation logic in FreeDataPtrAttrs to directly free pointers from m_tRefMatch. This simplifies memory management and ensures proper cleanup of allocated data pointers.
Linux debug test results1 140 tests 1 082 ✅ 52m 43s ⏱️ For more details on these failures, see this check. Results for commit 2d158a0. |
Linux release test results1 140 tests 1 082 ✅ 14m 57s ⏱️ For more details on these failures, see this check. Results for commit 2d158a0. |
clt❌ CLT tests in Failed tests:🔧 Edit failed tests in UI: test/clt-tests/sharding/cluster/test-drop-sharded-clustering-table.rec––– input –––
export INSTANCE=1
––– output –––
OK
––– input –––
mkdir -p /var/{run,lib,log}/manticore-${INSTANCE}
––– output –––
OK
––– input –––
stdbuf -oL searchd -c test/clt-tests/base/searchd-with-flexible-ports.conf > /dev/null
––– output –––
OK
––– input –––
if timeout 10 grep -qm1 '\[BUDDY\] started' <(tail -n 1000 -f /var/log/manticore-${INSTANCE}/searchd.log); then echo 'Buddy started!'; else echo 'Timeout or failed!'; cat /var/log/manticore-${INSTANCE}/searchd.log; fi
––– output –––
OK
––– input –––
export INSTANCE=2
––– output –––
OK
––– input –––
mkdir -p /var/{run,lib,log}/manticore-${INSTANCE}
––– output –––
OK
––– input –––
stdbuf -oL searchd -c test/clt-tests/base/searchd-with-flexible-ports.conf > /dev/null
––– output –––
OK
––– input –––
if timeout 10 grep -qm1 '\[BUDDY\] started' <(tail -n 1000 -f /var/log/manticore-${INSTANCE}/searchd.log); then echo 'Buddy started!'; else echo 'Timeout or failed!'; cat /var/log/manticore-${INSTANCE}/searchd.log; fi
––– output –––
OK
––– input –––
export CLUSTER_NAME=c
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "create cluster ${CLUSTER_NAME}"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "show status like 'cluster_${CLUSTER_NAME}_status'\G"
––– output –––
OK
––– input –––
for n in `seq 2 $INSTANCE`; do mysql -h0 -P${n}306 -e "join cluster ${CLUSTER_NAME} at '127.0.0.1:1312'"; done;
––– output –––
OK
––– input –––
mysql -h0 -P${INSTANCE}306 -e "show status like 'cluster_${CLUSTER_NAME}_status'\G"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "create table ${CLUSTER_NAME}:tbl1(id bigint) shards='3' rf='2';"; echo $?;
––– output –––
OK
––– input –––
echo "=== Node 1306 ==="; mysql -h0 -P1306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 1306 failed!"; echo "=== Node 2306 ==="; mysql -h0 -P2306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 2306 failed!"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "DROP TABLE ${CLUSTER_NAME}:tbl1;"; echo $?;
––– output –––
OK
––– input –––
echo "=== Node 1306 ==="; mysql -h0 -P1306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 1306 failed!"; echo "=== Node 2306 ==="; mysql -h0 -P2306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 2306 failed!"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "create table ${CLUSTER_NAME}:Tbl2(id bigint) shards='3' rf='1';"; echo $?
––– output –––
OK
––– input –––
echo "=== Node 1306 ==="; mysql -h0 -P1306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 1306 failed!"; echo "=== Node 2306 ==="; mysql -h0 -P2306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 2306 failed!"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "DROP TABLE ${CLUSTER_NAME}:Tbl2;"; echo $?
––– output –––
OK
––– input –––
echo "=== Node 1306 ==="; mysql -h0 -P1306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 1306 failed!"; echo "=== Node 2306 ==="; mysql -h0 -P2306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 2306 failed!"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "create table ${CLUSTER_NAME}:tbl_missing_type(id) shards='3' rf='1';"
––– output –––
OK
––– input –––
echo "=== Node 1306 ==="; mysql -h0 -P1306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 1306 failed!"; echo "=== Node 2306 ==="; mysql -h0 -P2306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 2306 failed!"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "DROP TABLE ${CLUSTER_NAME}:tbl_missing_type;"; echo $?
––– output –––
OK
––– input –––
echo "=== Node 1306 ==="; mysql -h0 -P1306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 1306 failed!"; echo "=== Node 2306 ==="; mysql -h0 -P2306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 2306 failed!"
––– output –––
OK
––– input –––
LONG_TABLE_NAME=$(printf "tbl%065d" 1)
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "create table ${CLUSTER_NAME}:${LONG_TABLE_NAME}(id bigint) shards='3' rf='1';"
––– output –––
OK
––– input –––
echo "=== Node 1306 ==="; mysql -h0 -P1306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 1306 failed!"; echo "=== Node 2306 ==="; mysql -h0 -P2306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 2306 failed!"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "DROP TABLE ${CLUSTER_NAME}:${LONG_TABLE_NAME};"
––– output –––
+ ERROR 1064 (42000) at line 1: Waiting timeout exceeded.
––– input –––
echo "=== Node 1306 ==="; mysql -h0 -P1306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 1306 failed!"; echo "=== Node 2306 ==="; mysql -h0 -P2306 -e "SHOW TABLES\G" | sed 's/^[[:space:]]*//' || echo "Node 2306 failed!"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "DROP TABLE ${CLUSTER_NAME}:nonexistent_table;"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "DROP TABLE nonexistent_cluster:tbl1;"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "DROP TABLE ${CLUSTER_NAME}:tbl1;"
––– output –––
OK
––– input –––
mysql -h0 -P1306 -e "INSERT INTO ${CLUSTER_NAME}:tbl1 VALUES (1);" & sleep 1; mysql -h0 -P1306 -e "DROP TABLE ${CLUSTER_NAME}:tbl1;"
––– output –––
OK |
Windows test results 3 files 3 suites 29m 2s ⏱️ For more details on these failures, see this check. Results for commit 2d158a0. |
Related issue #3928