Skip to content

[Enhancement](memory) Add ConcurrentLong2ObjectHashMap and ConcurrentLong2LongHashMap#61332

Merged
dataroaring merged 7 commits intomasterfrom
feature/concurrent-fastutil-maps
Mar 31, 2026
Merged

[Enhancement](memory) Add ConcurrentLong2ObjectHashMap and ConcurrentLong2LongHashMap#61332
dataroaring merged 7 commits intomasterfrom
feature/concurrent-fastutil-maps

Conversation

@dataroaring
Copy link
Copy Markdown
Contributor

Summary

Add two thread-safe primitive-key concurrent hash maps built on fastutil, designed as drop-in replacements for ConcurrentHashMap<Long, V> and ConcurrentHashMap<Long, Long> in memory-sensitive FE paths.

  • ConcurrentLong2ObjectHashMap<V> — replaces ConcurrentHashMap<Long, V>
  • ConcurrentLong2LongHashMap — replaces ConcurrentHashMap<Long, Long>

Why

ConcurrentHashMap<Long, V> costs ~64 bytes per entry due to Long boxing, Node wrapper, and segment overhead. These fastutil-based maps reduce that to ~16 bytes per entry — a 4x memory reduction.

In Doris FE, several critical data structures use ConcurrentHashMap<Long, V> at tablet/partition scale (millions of entries), making this a significant memory optimization opportunity.

Design

  • Segment-based locking (default 16 segments) for concurrent throughput, similar to Java 7's ConcurrentHashMap design
  • Full Map interface compatibility for drop-in replacement
  • Atomic operations: putIfAbsent, computeIfAbsent, replace, remove(key, value)
  • Thread-safe iteration via snapshot-based entrySet()/keySet()/values()

Memory comparison

Collection Per-entry overhead 1M entries
ConcurrentHashMap<Long, V> ~64 bytes ~61 MB
ConcurrentLong2ObjectHashMap<V> ~16 bytes ~15 MB
ConcurrentHashMap<Long, Long> ~80 bytes ~76 MB
ConcurrentLong2LongHashMap ~16 bytes ~15 MB

Test plan

  • ConcurrentLong2ObjectHashMapTest — 432 lines covering put/get/remove, putIfAbsent, computeIfAbsent, replace, concurrent writes from multiple threads, iteration consistency, empty map edge cases
  • ConcurrentLong2LongHashMapTest — 455 lines covering CRUD, default value semantics, concurrent operations, atomic operations, iteration, edge cases

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings March 14, 2026 12:11
@Thearas
Copy link
Copy Markdown
Contributor

Thearas commented Mar 14, 2026

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?

Copy link
Copy Markdown
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

Adds two new segmented-lock concurrent hash maps for FE that use fastutil primitive-key/value maps to reduce memory overhead compared to ConcurrentHashMap<Long, ...> while preserving familiar APIs and providing snapshot-based iteration.

Changes:

  • Introduce ConcurrentLong2ObjectHashMap<V>: concurrent long→object map with per-segment RW locks and atomic compute/merge-style operations.
  • Introduce ConcurrentLong2LongHashMap: concurrent long→long map with per-segment RW locks plus an atomic addTo counter helper.
  • Add comprehensive JUnit tests for correctness, concurrency behavior, iteration snapshots, and Gson round-trip/format compatibility.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.

File Description
fe/fe-core/src/main/java/org/apache/doris/common/ConcurrentLong2ObjectHashMap.java New segmented concurrent long→object map implementation.
fe/fe-core/src/main/java/org/apache/doris/common/ConcurrentLong2LongHashMap.java New segmented concurrent long→long map implementation with addTo.
fe/fe-core/src/test/java/org/apache/doris/common/ConcurrentLong2ObjectHashMapTest.java New unit tests for object map behavior, concurrency, and Gson.
fe/fe-core/src/test/java/org/apache/doris/common/ConcurrentLong2LongHashMapTest.java New unit tests for long map behavior, concurrency, and Gson.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +263 to +269
if (seg.map.containsKey(key)) {
return seg.map.get(key);
}
long newValue = mappingFunction.applyAsLong(key);
seg.map.put(key, newValue);
return newValue;
} finally {
Comment on lines +451 to +453
// Boxed get via Map<Long,Long> interface returns null for missing keys
Long boxedResult = map.getOrDefault(999L, map.defaultReturnValue());
Assertions.assertEquals(0L, boxedResult);
Comment on lines +50 to +51
* <p><b>Important:</b> All compound operations from both {@link Long2LongMap} and {@link Map}
* interfaces are overridden to ensure atomicity within a segment's write lock.
Comment on lines +26 to +29
import it.unimi.dsi.fastutil.longs.LongBinaryOperator;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
Comment on lines +50 to +51
* <p><b>Important:</b> All compound operations (computeIfAbsent, computeIfPresent, compute, merge)
* from both {@link Long2ObjectMap} and {@link Map} interfaces are overridden to ensure atomicity
Comment on lines +223 to +227
void testNullValues() {
ConcurrentLong2ObjectHashMap<String> map = new ConcurrentLong2ObjectHashMap<>();
map.put(1L, null);
Assertions.assertTrue(map.containsKey(1L));
Assertions.assertNull(map.get(1L));
gavinchou
gavinchou previously approved these changes Mar 14, 2026
@github-actions github-actions bot added the approved Indicates a PR has been approved by one committer. label Mar 14, 2026
@github-actions
Copy link
Copy Markdown
Contributor

PR approved by at least one committer and no changes requested.

@github-actions
Copy link
Copy Markdown
Contributor

PR approved by anyone and no changes requested.

Copy link
Copy Markdown
Contributor Author

@dataroaring dataroaring left a comment

Choose a reason for hiding this comment

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

Thanks for the review! Addressed each comment below:

1. defaultReturnValue divergence (ConcurrentLong2LongHashMap)
Already documented in the class Javadoc (lines 48-50): "The defaultReturnValue is fixed at 0. Calling defaultReturnValue(long) on this wrapper will NOT propagate to the underlying segment maps, and reads/removes will still return 0 for missing keys."

2. Test comment mismatch (ConcurrentLong2LongHashMapTest:453)
The comment on line 454 ("Boxed get via Map<Long,Long> interface returns null for missing keys") applies to line 455 (assertNull(((Map<Long, Long>) map).get(999L))), not to the getOrDefault call above it. The comment is accurate.

3 & 7. Javadoc over-promises atomicity (both classes)
All compound operations from both Long2ObjectMap/Long2LongMap and Map interfaces are overridden:

  • computeIfAbsent (3 overloads: primitive, Long2*Function, boxed Function)
  • computeIfPresent
  • compute
  • merge
  • mergeLong (Long2Long only)
  • putIfAbsent
  • replace (both overloads)
  • remove(Object, Object)

The boxed Map-level variants like putIfAbsent(Long, V) delegate through fastutil's AbstractLong2ObjectMap bridge to our primitive overrides, so they are also atomic. The Javadoc is accurate.

4. Unused imports (LongBinaryOperator, ObjectArrayList)
These imports do not exist in the file. ConcurrentLong2LongHashMap uses java.util.function.LongBinaryOperator fully qualified at line 400. ObjectArrayList is imported and used in ConcurrentLong2ObjectHashMap (line 429). All imports in both files are used.

5 & 6. computeIfAbsent null handling (ConcurrentLong2ObjectHashMap)
Already handled correctly. Both overloads check if (newValue != null) before calling put (lines 282-285 and 301-304), matching the Map.computeIfAbsent contract.

8. Null value semantics
ConcurrentLong2ObjectHashMap already rejects null values — put, putIfAbsent, replace all call Objects.requireNonNull(value) (lines 173, 196, 208, 220). Unit test testNullValuesRejected() (line 224-230) verifies this behavior. This matches ConcurrentHashMap semantics.

@github-actions github-actions bot removed the approved Indicates a PR has been approved by one committer. label Mar 16, 2026
@dataroaring
Copy link
Copy Markdown
Contributor Author

run buildall

@dataroaring
Copy link
Copy Markdown
Contributor Author

run buildall

2 similar comments
@dataroaring
Copy link
Copy Markdown
Contributor Author

run buildall

@dataroaring
Copy link
Copy Markdown
Contributor Author

run buildall

@doris-robot
Copy link
Copy Markdown

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

------ Round 1 ----------------------------------
orders	Doris	NULL	NULL	0	0	0	NULL	0	NULL	NULL	2023-12-26 18:27:23	2023-12-26 18:42:55	NULL	utf-8	NULL	NULL	
============================================
q1	17602	4456	4266	4266
q2	q3	10642	776	518	518
q4	4676	350	244	244
q5	7559	1218	1004	1004
q6	171	173	145	145
q7	772	839	678	678
q8	9308	1464	1339	1339
q9	4925	4750	4720	4720
q10	6298	1895	1666	1666
q11	483	255	246	246
q12	740	581	460	460
q13	18055	2952	2191	2191
q14	232	234	209	209
q15	q16	731	749	668	668
q17	736	837	434	434
q18	6099	5421	5224	5224
q19	1113	963	616	616
q20	535	481	372	372
q21	4533	1823	1440	1440
q22	407	446	333	333
Total cold run time: 95617 ms
Total hot run time: 26773 ms

----- Round 2, with runtime_filter_mode=off -----
orders	Doris	NULL	NULL	150000000	42	6422171781	NULL	22778155	NULL	NULL	2023-12-26 18:27:23	2023-12-26 18:42:55	NULL	utf-8	NULL	NULL	
============================================
q1	4835	4546	4645	4546
q2	q3	3877	4417	3827	3827
q4	886	1200	833	833
q5	4065	4401	4350	4350
q6	189	170	141	141
q7	1736	1608	1532	1532
q8	2449	2743	2569	2569
q9	7667	7447	7430	7430
q10	3749	3959	3553	3553
q11	518	433	415	415
q12	490	598	433	433
q13	2682	3288	2341	2341
q14	274	291	303	291
q15	q16	752	789	768	768
q17	1201	1345	1363	1345
q18	7397	6935	6692	6692
q19	1010	985	1061	985
q20	2055	2136	2123	2123
q21	4019	3562	3277	3277
q22	480	429	386	386
Total cold run time: 50331 ms
Total hot run time: 47837 ms

@doris-robot
Copy link
Copy Markdown

TPC-DS: Total hot run time: 168447 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 b78116f98468bbe42f98a9d861eb8811f0c11190, data reload: false

query5	4336	629	502	502
query6	325	239	204	204
query7	4201	464	260	260
query8	343	245	217	217
query9	8688	2705	2694	2694
query10	538	408	336	336
query11	6992	5075	4880	4880
query12	186	129	123	123
query13	1286	478	369	369
query14	5776	3701	3477	3477
query14_1	2871	2819	2842	2819
query15	216	192	173	173
query16	974	503	467	467
query17	890	736	668	668
query18	2454	465	373	373
query19	215	212	195	195
query20	139	129	127	127
query21	215	148	112	112
query22	13254	14109	14644	14109
query23	16181	15754	15726	15726
query23_1	15740	15948	15479	15479
query24	7222	1643	1223	1223
query24_1	1212	1216	1232	1216
query25	613	455	416	416
query26	1230	254	142	142
query27	2773	481	289	289
query28	4495	1828	1841	1828
query29	834	573	481	481
query30	312	227	194	194
query31	1016	963	885	885
query32	83	69	70	69
query33	521	341	281	281
query34	882	866	531	531
query35	630	715	610	610
query36	1086	1103	982	982
query37	130	95	86	86
query38	2958	2931	2888	2888
query39	846	838	817	817
query39_1	793	784	807	784
query40	234	152	134	134
query41	62	58	58	58
query42	259	256	253	253
query43	244	242	222	222
query44	
query45	191	191	184	184
query46	878	991	597	597
query47	2083	2101	2077	2077
query48	307	313	228	228
query49	638	469	383	383
query50	703	280	212	212
query51	4115	4091	3957	3957
query52	269	263	257	257
query53	286	334	276	276
query54	308	273	275	273
query55	97	93	92	92
query56	335	328	321	321
query57	1945	1756	1574	1574
query58	279	278	273	273
query59	2780	2938	2772	2772
query60	348	346	326	326
query61	159	154	150	150
query62	631	590	541	541
query63	319	286	278	278
query64	4991	1263	1005	1005
query65	
query66	1469	452	360	360
query67	24164	24230	24157	24157
query68	
query69	399	303	284	284
query70	995	977	945	945
query71	347	311	303	303
query72	2730	2583	2454	2454
query73	547	540	317	317
query74	9539	9627	9428	9428
query75	2872	2762	2486	2486
query76	2278	1022	677	677
query77	363	393	324	324
query78	10915	11022	10430	10430
query79	3168	745	581	581
query80	1751	632	555	555
query81	581	262	223	223
query82	980	154	118	118
query83	333	257	243	243
query84	307	124	103	103
query85	921	519	461	461
query86	509	301	293	293
query87	3136	3120	3074	3074
query88	3560	2664	2670	2664
query89	430	369	349	349
query90	2227	183	192	183
query91	173	168	142	142
query92	96	75	68	68
query93	2075	866	500	500
query94	658	324	281	281
query95	598	410	331	331
query96	648	505	225	225
query97	2434	2502	2420	2420
query98	249	226	229	226
query99	1006	997	907	907
Total cold run time: 252635 ms
Total hot run time: 168447 ms

@dataroaring
Copy link
Copy Markdown
Contributor Author

run buildall

1 similar comment
@dataroaring
Copy link
Copy Markdown
Contributor Author

run buildall

@doris-robot
Copy link
Copy Markdown

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

------ Round 1 ----------------------------------
orders	Doris	NULL	NULL	0	0	0	NULL	0	NULL	NULL	2023-12-26 18:27:23	2023-12-26 18:42:55	NULL	utf-8	NULL	NULL	
============================================
q1	17653	4445	4272	4272
q2	q3	10650	750	513	513
q4	4671	369	248	248
q5	7563	1210	1029	1029
q6	175	174	145	145
q7	787	841	668	668
q8	9697	1456	1302	1302
q9	5132	4735	4732	4732
q10	6327	1912	1659	1659
q11	454	243	238	238
q12	754	584	476	476
q13	18043	3003	2162	2162
q14	231	237	216	216
q15	q16	738	729	664	664
q17	736	861	433	433
q18	5926	5421	5141	5141
q19	1179	972	630	630
q20	528	505	371	371
q21	4554	1825	1490	1490
q22	467	368	294	294
Total cold run time: 96265 ms
Total hot run time: 26683 ms

----- Round 2, with runtime_filter_mode=off -----
orders	Doris	NULL	NULL	150000000	42	6422171781	NULL	22778155	NULL	NULL	2023-12-26 18:27:23	2023-12-26 18:42:55	NULL	utf-8	NULL	NULL	
============================================
q1	4752	4556	4686	4556
q2	q3	3846	4344	3803	3803
q4	891	1202	786	786
q5	4054	4350	4348	4348
q6	195	178	138	138
q7	1787	1667	1541	1541
q8	2498	2743	2628	2628
q9	7545	7417	7435	7417
q10	3791	3973	3627	3627
q11	525	453	447	447
q12	497	589	453	453
q13	2717	3328	2435	2435
q14	272	285	267	267
q15	q16	729	764	718	718
q17	1182	1364	1692	1364
q18	7278	6840	6616	6616
q19	964	886	976	886
q20	2149	2113	1982	1982
q21	3951	3481	3356	3356
q22	473	427	382	382
Total cold run time: 50096 ms
Total hot run time: 47750 ms

@doris-robot
Copy link
Copy Markdown

TPC-DS: Total hot run time: 168565 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 b78116f98468bbe42f98a9d861eb8811f0c11190, data reload: false

query5	4325	651	507	507
query6	335	224	200	200
query7	4216	466	262	262
query8	337	248	230	230
query9	8696	2749	2706	2706
query10	532	392	361	361
query11	6951	5070	4910	4910
query12	194	135	123	123
query13	1273	466	355	355
query14	5791	3695	3583	3583
query14_1	2853	2826	2803	2803
query15	200	197	178	178
query16	980	461	463	461
query17	903	729	627	627
query18	2460	471	343	343
query19	233	211	182	182
query20	136	125	124	124
query21	213	139	107	107
query22	13144	13980	14773	13980
query23	16644	15923	15502	15502
query23_1	15690	15762	15559	15559
query24	7111	1624	1241	1241
query24_1	1226	1208	1214	1208
query25	543	472	399	399
query26	1244	269	152	152
query27	2762	499	297	297
query28	4450	1851	1838	1838
query29	877	584	477	477
query30	296	226	192	192
query31	1049	951	886	886
query32	77	72	67	67
query33	507	348	284	284
query34	890	873	533	533
query35	668	701	613	613
query36	1079	1136	1003	1003
query37	139	99	83	83
query38	3003	3009	2905	2905
query39	867	844	823	823
query39_1	805	792	794	792
query40	233	160	134	134
query41	63	60	58	58
query42	260	255	258	255
query43	251	257	228	228
query44	
query45	195	190	197	190
query46	891	973	605	605
query47	2577	2163	2074	2074
query48	332	321	234	234
query49	634	455	385	385
query50	695	281	214	214
query51	4044	4017	3990	3990
query52	262	261	262	261
query53	289	338	291	291
query54	305	265	270	265
query55	90	86	83	83
query56	341	331	317	317
query57	1913	1806	1741	1741
query58	292	278	276	276
query59	2760	2955	2724	2724
query60	344	341	328	328
query61	153	144	149	144
query62	632	593	551	551
query63	310	276	280	276
query64	5087	1288	1001	1001
query65	
query66	1458	449	358	358
query67	24314	24246	24136	24136
query68	
query69	405	317	283	283
query70	957	967	940	940
query71	335	311	308	308
query72	2776	2874	2561	2561
query73	553	548	332	332
query74	9596	9531	9410	9410
query75	2851	2747	2468	2468
query76	2299	1029	693	693
query77	382	405	319	319
query78	10933	11038	10428	10428
query79	2676	777	581	581
query80	1788	661	592	592
query81	545	267	236	236
query82	1002	161	123	123
query83	353	269	249	249
query84	309	160	106	106
query85	910	487	466	466
query86	423	340	282	282
query87	3176	3095	3050	3050
query88	3587	2672	2669	2669
query89	421	359	352	352
query90	2013	185	186	185
query91	165	165	145	145
query92	80	78	74	74
query93	1131	850	495	495
query94	646	318	283	283
query95	592	411	324	324
query96	656	543	231	231
query97	2484	2479	2402	2402
query98	235	225	242	225
query99	996	995	921	921
Total cold run time: 251494 ms
Total hot run time: 168565 ms

Copy link
Copy Markdown
Contributor

@morrySnow morrySnow left a comment

Choose a reason for hiding this comment

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

move to fe-foundation module

@dataroaring dataroaring force-pushed the feature/concurrent-fastutil-maps branch from b78116f to 5470db4 Compare March 25, 2026 06:32
@dataroaring
Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen
Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage `` 🎉
Increment coverage report
Complete coverage report

dataroaring and others added 2 commits March 25, 2026 07:07
…Long2LongHashMap

Add thread-safe primitive-key concurrent hash maps built on fastutil,
designed to replace ConcurrentHashMap<Long, V> and ConcurrentHashMap<Long, Long>
in memory-sensitive FE paths.

These maps eliminate Long autoboxing overhead and reduce per-entry memory
from ~64 bytes (ConcurrentHashMap) to ~16 bytes, a 4x improvement.

Key design:
- Segment-based locking (default 16 segments) for concurrent throughput
- Full Map interface compatibility for drop-in replacement
- Atomic putIfAbsent, computeIfAbsent, replace, remove operations
- Comprehensive unit tests covering CRUD, concurrency, iteration,
  edge cases, and default value semantics

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Override defaultReturnValue(long) in ConcurrentLong2LongHashMap to
  throw UnsupportedOperationException, preventing silent divergence
  between wrapper and segment maps
- Import LongBinaryOperator instead of using fully-qualified name
- Tighten Javadoc in both classes to precisely describe atomicity scope
- Add test for defaultReturnValue rejection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dataroaring and others added 3 commits March 25, 2026 07:07
- Replace HashCommon.mix(long) with inline Murmur3 64-bit finalizer to
  avoid dependency on specific fastutil version's API
- Remove @OverRide from methods that are default on the interface but
  not present in AbstractLong2LongMap/AbstractLong2ObjectMap, which
  varies across fastutil versions
- Self-implement putIfAbsent/replace/getOrDefault instead of delegating
  to underlying map methods that may not exist in older versions
- Remove explicit fastutil-core dependency since fastutil 8.5.12 is
  already available transitively via trino-main

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Disambiguate forEach lambda with explicit functional interface cast
- Use Long.valueOf() to avoid ambiguous put(Long,V) vs put(long,V)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…module

Address reviewer feedback (morrySnow): move ConcurrentLong2ObjectHashMap
and ConcurrentLong2LongHashMap from fe-core/common to fe-foundation/util.
Add fastutil-core dependency to fe-foundation pom.xml.
Tests remain in fe-core as they depend on GsonUtils for serialization tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dataroaring dataroaring force-pushed the feature/concurrent-fastutil-maps branch from 5470db4 to 3fae82b Compare March 25, 2026 14:07
@dataroaring
Copy link
Copy Markdown
Contributor Author

run buildall

hive-catalog-shade bundles an ancient (~7.x) fastutil without package
relocation. When fastutil-core was only a transitive dependency (via
fe-foundation), the classloader could pick up the old
Long2ObjectOpenHashMap from hive-catalog-shade first, which lacks
computeIfAbsent(), causing NoSuchMethodError at runtime.

Keeping fastutil-core as a direct dependency ensures it appears before
hive-catalog-shade on the classpath.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dataroaring
Copy link
Copy Markdown
Contributor Author

run buildall

@doris-robot
Copy link
Copy Markdown

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

------ Round 1 ----------------------------------
orders	Doris	NULL	NULL	0	0	0	NULL	0	NULL	NULL	2023-12-26 18:27:23	2023-12-26 18:42:55	NULL	utf-8	NULL	NULL	
============================================
q1	17663	4459	4333	4333
q2	q3	10649	758	515	515
q4	4678	343	247	247
q5	7563	1191	1001	1001
q6	173	174	143	143
q7	787	844	671	671
q8	9694	1508	1310	1310
q9	5363	4645	4650	4645
q10	6334	1903	1622	1622
q11	441	241	236	236
q12	743	565	456	456
q13	18031	2715	1965	1965
q14	224	239	208	208
q15	q16	738	716	662	662
q17	724	836	449	449
q18	6173	5357	5162	5162
q19	1150	977	628	628
q20	532	478	376	376
q21	4495	1820	1400	1400
q22	502	385	280	280
Total cold run time: 96657 ms
Total hot run time: 26309 ms

----- Round 2, with runtime_filter_mode=off -----
orders	Doris	NULL	NULL	150000000	42	6422171781	NULL	22778155	NULL	NULL	2023-12-26 18:27:23	2023-12-26 18:42:55	NULL	utf-8	NULL	NULL	
============================================
q1	4800	4685	4591	4591
q2	q3	3890	4357	3847	3847
q4	936	1237	783	783
q5	4050	4372	4345	4345
q6	189	178	145	145
q7	1758	1604	1560	1560
q8	2501	2777	2585	2585
q9	7524	7327	7455	7327
q10	3835	4022	3565	3565
q11	513	426	422	422
q12	484	573	450	450
q13	2476	3144	2322	2322
q14	287	311	286	286
q15	q16	732	776	724	724
q17	1186	1404	1377	1377
q18	7048	6770	6787	6770
q19	982	964	936	936
q20	2071	2150	2022	2022
q21	3901	3457	3289	3289
q22	434	415	379	379
Total cold run time: 49597 ms
Total hot run time: 47725 ms

@doris-robot
Copy link
Copy Markdown

TPC-DS: Total hot run time: 168823 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 f49d1e7629aa582c8998bb32cd849a382b1bba31, data reload: false

query5	4342	618	510	510
query6	333	226	209	209
query7	4222	470	277	277
query8	344	237	223	223
query9	8698	2680	2679	2679
query10	485	368	337	337
query11	6973	5087	4862	4862
query12	188	135	121	121
query13	1301	471	353	353
query14	5685	3704	3406	3406
query14_1	2881	2850	2804	2804
query15	209	200	177	177
query16	977	470	450	450
query17	1124	726	629	629
query18	2461	445	361	361
query19	227	212	188	188
query20	141	126	128	126
query21	221	135	111	111
query22	13420	13910	14392	13910
query23	16732	16179	16347	16179
query23_1	16120	15830	15649	15649
query24	7129	1600	1234	1234
query24_1	1226	1237	1227	1227
query25	601	521	397	397
query26	1228	262	153	153
query27	2786	495	293	293
query28	4978	1839	1881	1839
query29	868	572	478	478
query30	310	238	192	192
query31	1011	974	872	872
query32	80	71	70	70
query33	505	350	287	287
query34	907	908	534	534
query35	656	691	609	609
query36	1097	1160	990	990
query37	142	98	83	83
query38	2933	2889	2868	2868
query39	860	839	807	807
query39_1	792	798	790	790
query40	227	150	139	139
query41	62	59	58	58
query42	253	255	254	254
query43	237	249	216	216
query44	
query45	198	186	183	183
query46	891	973	597	597
query47	2557	2503	2102	2102
query48	332	312	231	231
query49	632	459	388	388
query50	695	280	210	210
query51	4091	4070	3972	3972
query52	269	264	258	258
query53	290	328	280	280
query54	286	279	262	262
query55	88	86	86	86
query56	311	324	312	312
query57	1889	1833	1770	1770
query58	278	269	270	269
query59	2781	2944	2755	2755
query60	346	334	322	322
query61	166	157	157	157
query62	606	587	541	541
query63	311	274	275	274
query64	5145	1303	1019	1019
query65	
query66	1461	452	353	353
query67	24187	24279	24283	24279
query68	
query69	408	309	291	291
query70	944	940	956	940
query71	334	317	292	292
query72	2844	2709	2484	2484
query73	551	559	313	313
query74	9689	9614	9434	9434
query75	2874	2734	2478	2478
query76	2293	1023	664	664
query77	359	378	308	308
query78	10940	11130	10414	10414
query79	1109	756	577	577
query80	1375	624	529	529
query81	574	261	225	225
query82	1037	151	117	117
query83	368	262	238	238
query84	248	118	101	101
query85	914	515	453	453
query86	418	305	294	294
query87	3136	3139	2999	2999
query88	3545	2652	2651	2651
query89	429	366	351	351
query90	1974	171	174	171
query91	178	171	140	140
query92	79	76	73	73
query93	930	900	515	515
query94	639	327	306	306
query95	576	340	312	312
query96	636	507	233	233
query97	2471	2463	2400	2400
query98	231	225	221	221
query99	996	938	907	907
Total cold run time: 251233 ms
Total hot run time: 168823 ms

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.

should move to fe-foundation too

Tests for ConcurrentLong2ObjectHashMap and ConcurrentLong2LongHashMap
were in fe-core but the source classes live in fe-foundation. Move them
to the correct module and replace GsonUtils.GSON with new Gson() to
remove the cross-module dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dataroaring
Copy link
Copy Markdown
Contributor Author

run buildall

@doris-robot
Copy link
Copy Markdown

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

------ Round 1 ----------------------------------
orders	Doris	NULL	NULL	0	0	0	NULL	0	NULL	NULL	2023-12-26 18:27:23	2023-12-26 18:42:55	NULL	utf-8	NULL	NULL	
============================================
q1	17595	4491	4269	4269
q2	q3	10653	777	518	518
q4	4684	361	248	248
q5	7567	1219	1048	1048
q6	179	175	147	147
q7	805	825	678	678
q8	9299	1446	1304	1304
q9	4880	4712	4706	4706
q10	6233	1889	1650	1650
q11	469	264	237	237
q12	716	580	476	476
q13	18033	2721	1976	1976
q14	230	236	209	209
q15	q16	717	742	661	661
q17	735	848	442	442
q18	6042	5371	5197	5197
q19	1127	980	613	613
q20	540	493	374	374
q21	4360	1849	1401	1401
q22	350	302	246	246
Total cold run time: 95214 ms
Total hot run time: 26400 ms

----- Round 2, with runtime_filter_mode=off -----
orders	Doris	NULL	NULL	150000000	42	6422171781	NULL	22778155	NULL	NULL	2023-12-26 18:27:23	2023-12-26 18:42:55	NULL	utf-8	NULL	NULL	
============================================
q1	5015	4651	4560	4560
q2	q3	3894	4393	3816	3816
q4	894	1217	763	763
q5	4055	4356	4373	4356
q6	184	179	140	140
q7	1749	1665	1529	1529
q8	2466	2651	2567	2567
q9	7691	7624	7416	7416
q10	3798	4022	3626	3626
q11	524	452	412	412
q12	486	598	444	444
q13	2397	2885	2033	2033
q14	295	296	273	273
q15	q16	731	784	703	703
q17	1178	1277	1373	1277
q18	7454	6854	6595	6595
q19	922	919	955	919
q20	2071	2164	1977	1977
q21	4012	3678	3353	3353
q22	437	436	376	376
Total cold run time: 50253 ms
Total hot run time: 47135 ms

@doris-robot
Copy link
Copy Markdown

TPC-DS: Total hot run time: 168750 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 bae76abe915e1ef35b14daf6f665242add61ef91, data reload: false

query5	4325	643	493	493
query6	339	235	200	200
query7	4203	494	271	271
query8	351	261	225	225
query9	8700	2664	2729	2664
query10	553	419	335	335
query11	7062	5123	4907	4907
query12	182	126	123	123
query13	1266	454	330	330
query14	5769	3759	3481	3481
query14_1	2874	2796	2800	2796
query15	210	191	172	172
query16	973	473	458	458
query17	925	695	628	628
query18	2436	433	341	341
query19	232	214	199	199
query20	132	123	123	123
query21	210	131	114	114
query22	13279	14094	14786	14094
query23	16851	16208	15876	15876
query23_1	16213	15658	15727	15658
query24	7224	1596	1213	1213
query24_1	1235	1244	1228	1228
query25	588	505	447	447
query26	1248	264	154	154
query27	2786	480	302	302
query28	4500	1841	1838	1838
query29	846	598	503	503
query30	305	228	193	193
query31	1024	946	886	886
query32	84	72	76	72
query33	531	341	297	297
query34	905	867	520	520
query35	645	697	597	597
query36	1087	1162	999	999
query37	140	100	89	89
query38	3018	2961	2838	2838
query39	871	829	817	817
query39_1	800	798	789	789
query40	242	161	142	142
query41	76	112	60	60
query42	272	258	254	254
query43	243	246	220	220
query44	
query45	200	189	184	184
query46	892	965	616	616
query47	2107	2134	2038	2038
query48	313	314	227	227
query49	628	443	369	369
query50	719	273	213	213
query51	4032	4055	3983	3983
query52	263	267	255	255
query53	291	335	283	283
query54	312	271	264	264
query55	94	88	81	81
query56	310	342	315	315
query57	1882	1736	1839	1736
query58	284	276	269	269
query59	2788	2949	2744	2744
query60	340	333	308	308
query61	159	154	150	150
query62	642	592	537	537
query63	301	274	275	274
query64	4943	1304	1005	1005
query65	
query66	1480	454	356	356
query67	24234	24395	24298	24298
query68	
query69	417	308	295	295
query70	944	968	883	883
query71	338	303	307	303
query72	2864	2701	2413	2413
query73	537	546	325	325
query74	9632	9566	9399	9399
query75	2852	2763	2469	2469
query76	2297	1053	670	670
query77	375	396	323	323
query78	10986	11152	10445	10445
query79	1072	817	568	568
query80	708	621	584	584
query81	500	259	226	226
query82	1356	152	123	123
query83	322	257	239	239
query84	287	121	100	100
query85	854	494	465	465
query86	376	302	305	302
query87	3138	3109	3039	3039
query88	3563	2655	2652	2652
query89	436	367	342	342
query90	1962	179	188	179
query91	170	164	140	140
query92	80	77	73	73
query93	929	880	505	505
query94	464	331	307	307
query95	597	415	309	309
query96	649	517	232	232
query97	2474	2476	2422	2422
query98	227	239	219	219
query99	995	992	842	842
Total cold run time: 249557 ms
Total hot run time: 168750 ms

@github-actions github-actions bot added the approved Indicates a PR has been approved by one committer. label Mar 30, 2026
@github-actions
Copy link
Copy Markdown
Contributor

PR approved by at least one committer and no changes requested.

@dataroaring dataroaring merged commit 3914128 into master Mar 31, 2026
31 of 33 checks passed
morningman pushed a commit that referenced this pull request Apr 2, 2026
…Long2LongHashMap (#61332)

## Summary

Add two thread-safe primitive-key concurrent hash maps built on
fastutil, designed as drop-in replacements for `ConcurrentHashMap<Long,
V>` and `ConcurrentHashMap<Long, Long>` in memory-sensitive FE paths.

- **`ConcurrentLong2ObjectHashMap<V>`** — replaces
`ConcurrentHashMap<Long, V>`
- **`ConcurrentLong2LongHashMap`** — replaces `ConcurrentHashMap<Long,
Long>`

### Why

`ConcurrentHashMap<Long, V>` costs ~64 bytes per entry due to Long
boxing, Node wrapper, and segment overhead. These fastutil-based maps
reduce that to ~16 bytes per entry — a **4x memory reduction**.

In Doris FE, several critical data structures use
`ConcurrentHashMap<Long, V>` at tablet/partition scale (millions of
entries), making this a significant memory optimization opportunity.

### Design

- **Segment-based locking** (default 16 segments) for concurrent
throughput, similar to Java 7's ConcurrentHashMap design
- Full `Map` interface compatibility for drop-in replacement
- Atomic operations: `putIfAbsent`, `computeIfAbsent`, `replace`,
`remove(key, value)`
- Thread-safe iteration via snapshot-based
`entrySet()`/`keySet()`/`values()`

### Memory comparison

| Collection | Per-entry overhead | 1M entries |
|------------|-------------------|------------|
| `ConcurrentHashMap<Long, V>` | ~64 bytes | ~61 MB |
| `ConcurrentLong2ObjectHashMap<V>` | ~16 bytes | ~15 MB |
| `ConcurrentHashMap<Long, Long>` | ~80 bytes | ~76 MB |
| `ConcurrentLong2LongHashMap` | ~16 bytes | ~15 MB |

## Test plan

- [x] `ConcurrentLong2ObjectHashMapTest` — 432 lines covering
put/get/remove, putIfAbsent, computeIfAbsent, replace, concurrent writes
from multiple threads, iteration consistency, empty map edge cases
- [x] `ConcurrentLong2LongHashMapTest` — 455 lines covering CRUD,
default value semantics, concurrent operations, atomic operations,
iteration, edge cases

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by one committer. dev/4.1.x dev/4.1.x-conflict reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants