Skip to content

[refactor](storage) extract RowKeyEncoder: dedup key encoding across both segment writers#65492

Open
csun5285 wants to merge 2 commits into
apache:masterfrom
csun5285:refactor/row-key-encoder
Open

[refactor](storage) extract RowKeyEncoder: dedup key encoding across both segment writers#65492
csun5285 wants to merge 2 commits into
apache:masterfrom
csun5285:refactor/row-key-encoder

Conversation

@csun5285

Copy link
Copy Markdown
Contributor

Both writers now hold a RowKeyEncoder member and _generate_primary_key_index loses its coder parameter. BlockAggregator's calls into the writer's encode helpers in partial_update_info.cpp are redirected onto the writer's _key_encoder (decoupling BlockAggregator from the writer entirely is left to a follow-up).

What problem does this PR solve?

Issue Number: close #xxx

Related PR: #xxx

Problem Summary:

Release note

None

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason
  • Behavior changed:

    • No.
    • Yes.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

…both segment writers

SegmentWriter and VerticalSegmentWriter carry two verbatim copies of the
row-key encoding logic (_full_encode_keys x2, _encode_seq_column,
_encode_rowid, _encode_keys, plus six coder members each). Extract it into
a shared RowKeyEncoder (be/src/storage/key/row_key_encoder.{h,cpp}) with
the two views made explicit:

- full_encode() / encode_short_keys(): the sort-key view (cluster key
  columns for mow tables with cluster keys, schema key columns otherwise)
- full_encode_primary_keys(): the primary-key view (always the schema key
  columns; the primary key index is built on these even when the segment
  sorts by cluster keys)
- append_seq_suffix() / append_rowid_suffix(): the two key suffixes

Both writers now hold a RowKeyEncoder member and _generate_primary_key_index
loses its coder parameter. BlockAggregator's calls into the writer's encode
helpers in partial_update_info.cpp are redirected onto the writer's
_key_encoder (decoupling BlockAggregator from the writer entirely is left
to a follow-up).

Equivalence notes for review:
- SegmentWriter's _full_encode_keys had a null_first parameter that no
  caller ever set to false; the encoder always uses the null-first marker.
- The constructor DCHECK(num_sort_key_columns >= num_short_key_columns) is
  dropped; both counts now derive from TabletSchema in one place.
- SegmentWriter::set_mow_context had zero callers and is removed.
- _maybe_invalid_row_cache intentionally stays in the writers; moving the
  row-cache invalidation is out of scope here.

Tests: row_key_encoder_test.cpp with 30 cases - 13 behavior cases (marker
layout, null-first ordering, sort-key vs primary-key views, short-key
truncation and collision, seq/rowid suffixes) plus a golden byte matrix
that pins the encoded bytes of every legal key-column type (TINYINT,
SMALLINT, INT, BIGINT, LARGEINT, BOOL, DATEV2, DATETIMEV2, DECIMAL32/64/
128I/256, IPV4, IPV6, CHAR, VARCHAR, STRING) in all three views as literal
hex strings, so any coder change or CPU-architecture drift fails loudly.
Every existing MoW / partial-update / pk-index UT now executes through
RowKeyEncoder.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@csun5285

Copy link
Copy Markdown
Contributor Author

run buildall

@csun5285

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review completed with one inline issue.

Critical checkpoint conclusions:

  • Goal/refactor: the RowKeyEncoder extraction preserves the old writer-local full-key, short-key, sequence-suffix, cluster-key primary-key separation, and rowid-suffix flows based on static comparison with GitHub base snapshots.
  • Scope: the production changes are focused in BE storage key/segment writer paths; I did not find another substantiated production correctness issue.
  • Concurrency/lifecycle: no new shared mutable state, thread entry, lock ordering, or special lifetime boundary was introduced by the helper; it stores schema-derived coder pointers like the old writers did.
  • Config/compatibility/persistence: no config, protocol, edit-log, or storage-format change was found; the encoded byte layout is covered by new unit-test goldens.
  • Parallel paths: SegmentWriter, VerticalSegmentWriter, and BlockAggregator call paths were checked, including cluster-key and sequence-column paths.
  • Tests/style: one test hygiene issue remains: the new unit test leaks private/protected macros into later includes.
  • User focus: no additional user-provided focus was present.

Validation was static only: this checkout is missing .worktree_initialized, thirdparty/installed, thirdparty/installed/bin/protoc, and clang-format v16, and the base commit is not present locally. I used GitHub PR metadata/base snapshots for diff scope. git show --check reported no whitespace errors on the changed files.

Subagent conclusions: tests-session-config proposed TSC-001, accepted as MAIN-001 and submitted inline. optimizer-rewrite found no candidates. Convergence round 1 ended with both live subagents returning NO_NEW_VALUABLE_FINDINGS for the final one-comment ledger set.

Comment thread be/test/storage/key/row_key_encoder_test.cpp
… only

Address review: the white-box macros were defined before every include of
the test TU, so gtest, standard and other Doris headers were all parsed
with rewritten access specifiers. Wrap only storage/tablet/tablet_schema.h
(the one header the test needs white-box access to) and #undef right after,
following the convention of segment_iterator_limit_opt_test.cpp.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@csun5285

Copy link
Copy Markdown
Contributor Author

run buildall

@csun5285

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review summary:

I found one test-coverage issue in the new RowKeyEncoder unit test. The production refactor itself looks byte-compatible with the removed SegmentWriter/VerticalSegmentWriter helper logic after checking full-key, short-key, null, sequence, rowid, cluster-key MoW, partial-update reachability, min/max, and lookup-side consumers.

Critical checkpoint conclusions:

  • Goal/test proof: the refactor has focused unit coverage for marker layout, suffixes, short keys, and many key coders, but the cluster-key separation test does not prove the primary-vs-sort coder split.
  • Scope: the implementation is focused on extracting key encoding into RowKeyEncoder and replacing the writer-local helpers.
  • Concurrency/lifecycle/config/persistence/FE-BE protocol: no new concurrency, dynamic config, persistence format, or protocol surface was introduced.
  • Parallel paths: SegmentWriter and VerticalSegmentWriter were both updated; partial-update and lookup-side paths were checked for compatibility.
  • Data correctness: no production key byte-layout or accessor-routing bug was substantiated.
  • Tests: one targeted test needs strengthening; no build/tests were run because the review prompt explicitly restricts this task to review operations.
  • User focus: no additional user-provided review focus was supplied.


// With cluster keys the segment sorts by the cluster key columns, while the
// primary key index is still built over the schema key columns.
TEST_F(RowKeyEncoderTest, ClusterKeySortDiffersFromPrimaryKeys) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This test does not actually catch the primary-vs-cluster coder mixup that the refactor is trying to protect against. cluster_key_schema() makes both the primary key and the cluster key INT columns, and this assertion only proves that encoded value 5 differs from encoded value 99. If full_encode_primary_keys() accidentally used the cluster/sort-key coder vector, the test would still pass because the supplied primary-key accessor is also INT. Please make this case heterogeneous, for example INT primary key plus CHAR/VARCHAR cluster key, and assert the exact hex for full_encode_primary_keys(primary_keys), full_encode(sort_keys), and the short key so a wrong coder vector fails deterministically.

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 95.24% (120/126) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 73.18% (29544/40369)
Line Coverage 56.82% (320356/563774)
Region Coverage 53.24% (266414/500426)
Branch Coverage 54.27% (117392/216307)

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29969 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 8802f5ea042363d0a60ff6ae4dda678f57a25fe4, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17680	4305	4125	4125
q2	2062	324	209	209
q3	10265	1432	842	842
q4	4679	525	340	340
q5	7503	871	594	594
q6	188	171	138	138
q7	777	856	622	622
q8	9346	1638	1603	1603
q9	5686	4438	4442	4438
q10	6778	1813	1546	1546
q11	494	345	317	317
q12	705	541	439	439
q13	18109	3373	2764	2764
q14	269	259	240	240
q15	q16	789	780	712	712
q17	938	982	958	958
q18	7012	5770	5749	5749
q19	1331	1310	1057	1057
q20	740	658	525	525
q21	5970	2587	2450	2450
q22	436	356	301	301
Total cold run time: 101757 ms
Total hot run time: 29969 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4364	4299	4254	4254
q2	286	312	214	214
q3	4565	4932	4401	4401
q4	2054	2092	1385	1385
q5	4531	4314	4362	4314
q6	231	170	129	129
q7	1713	2127	1771	1771
q8	2564	2247	2163	2163
q9	8328	8252	7962	7962
q10	4775	4733	4257	4257
q11	598	417	380	380
q12	759	775	540	540
q13	3315	3577	2863	2863
q14	307	315	265	265
q15	q16	700	736	651	651
q17	1324	1321	1427	1321
q18	7769	7233	7432	7233
q19	1142	1109	1072	1072
q20	2198	2202	1929	1929
q21	5230	4500	4372	4372
q22	518	449	420	420
Total cold run time: 57271 ms
Total hot run time: 51896 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 180905 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 8802f5ea042363d0a60ff6ae4dda678f57a25fe4, data reload: false

query5	4310	651	483	483
query6	455	233	204	204
query7	4851	564	329	329
query8	335	187	192	187
query9	8772	4109	4074	4074
query10	478	345	296	296
query11	5933	2376	2149	2149
query12	156	103	100	100
query13	1247	603	453	453
query14	6210	5313	4951	4951
query14_1	4312	4266	4317	4266
query15	216	222	178	178
query16	1002	497	453	453
query17	955	741	618	618
query18	2437	477	353	353
query19	211	209	158	158
query20	114	109	107	107
query21	232	160	132	132
query22	13686	13594	13404	13404
query23	17344	16601	16208	16208
query23_1	16309	16192	16217	16192
query24	7636	1775	1323	1323
query24_1	1349	1340	1295	1295
query25	571	477	405	405
query26	1322	369	215	215
query27	2672	609	374	374
query28	4407	2036	2044	2036
query29	1094	641	502	502
query30	344	268	229	229
query31	1111	1102	992	992
query32	109	64	62	62
query33	526	325	270	270
query34	1204	1159	689	689
query35	785	779	685	685
query36	1375	1353	1227	1227
query37	161	111	97	97
query38	1893	1705	1665	1665
query39	917	905	899	899
query39_1	877	870	882	870
query40	245	174	139	139
query41	67	63	63	63
query42	92	90	91	90
query43	327	336	277	277
query44	1419	806	780	780
query45	203	190	179	179
query46	1086	1254	744	744
query47	2425	2344	2226	2226
query48	406	400	307	307
query49	571	430	312	312
query50	1038	433	333	333
query51	10822	10769	10688	10688
query52	92	87	75	75
query53	276	284	199	199
query54	281	258	224	224
query55	81	76	67	67
query56	285	318	286	286
query57	1445	1419	1325	1325
query58	303	311	253	253
query59	1610	1644	1427	1427
query60	304	275	254	254
query61	151	146	157	146
query62	696	651	592	592
query63	241	208	209	208
query64	2859	1059	865	865
query65	4871	4787	4981	4787
query66	1825	516	393	393
query67	29435	29328	29309	29309
query68	3020	1541	978	978
query69	400	312	271	271
query70	1093	942	961	942
query71	356	329	310	310
query72	3099	2774	2479	2479
query73	830	795	436	436
query74	5093	4964	4774	4774
query75	2626	2602	2218	2218
query76	2315	1209	813	813
query77	366	388	289	289
query78	12393	12294	11804	11804
query79	1431	1144	781	781
query80	1284	547	456	456
query81	549	323	283	283
query82	607	159	120	120
query83	387	321	299	299
query84	329	158	130	130
query85	949	611	526	526
query86	416	301	291	291
query87	1830	1832	1742	1742
query88	3737	2837	2807	2807
query89	453	417	361	361
query90	1923	207	196	196
query91	199	191	160	160
query92	64	57	58	57
query93	1755	1549	964	964
query94	719	363	310	310
query95	785	489	495	489
query96	1099	834	361	361
query97	2705	2677	2557	2557
query98	213	210	202	202
query99	1162	1189	1024	1024
Total cold run time: 265853 ms
Total hot run time: 180905 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25.22 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 8802f5ea042363d0a60ff6ae4dda678f57a25fe4, data reload: false

query1	0.01	0.01	0.01
query2	0.09	0.05	0.04
query3	0.25	0.14	0.13
query4	1.61	0.13	0.14
query5	0.25	0.27	0.24
query6	1.26	1.08	1.11
query7	0.04	0.01	0.01
query8	0.05	0.04	0.04
query9	0.39	0.32	0.32
query10	0.57	0.59	0.59
query11	0.20	0.15	0.14
query12	0.18	0.15	0.14
query13	0.48	0.47	0.49
query14	1.01	1.02	1.02
query15	0.62	0.63	0.60
query16	0.33	0.34	0.33
query17	1.12	1.09	1.15
query18	0.23	0.21	0.21
query19	2.01	1.94	2.01
query20	0.02	0.02	0.02
query21	15.45	0.23	0.13
query22	4.82	0.06	0.05
query23	16.11	0.32	0.12
query24	2.95	0.44	0.32
query25	0.11	0.05	0.05
query26	0.75	0.21	0.14
query27	0.05	0.04	0.04
query28	3.49	0.97	0.57
query29	12.48	4.11	3.26
query30	0.28	0.15	0.14
query31	2.77	0.61	0.30
query32	3.21	0.59	0.48
query33	3.11	3.17	3.20
query34	15.48	4.22	3.55
query35	3.52	3.56	3.56
query36	0.56	0.44	0.45
query37	0.09	0.06	0.06
query38	0.05	0.04	0.04
query39	0.03	0.03	0.03
query40	0.18	0.16	0.15
query41	0.09	0.03	0.02
query42	0.04	0.02	0.03
query43	0.05	0.04	0.03
Total cold run time: 96.39 s
Total hot run time: 25.22 s

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.

2 participants