@@ -37,7 +37,7 @@ TEST(MapSharedShreddingContextTest, FirstFileUsesKMax) {
3737
3838TEST (MapSharedShreddingContextTest, AdaptKAfterOneFile) {
3939 // After reporting stats from one file, K should adapt to
40- // min(max_row_width , K_max).
40+ // min(adaptive width , K_max).
4141 std::map<std::string, int32_t > field_to_k_max = {{" m" , 10 }};
4242 MapSharedShreddingContext context (field_to_k_max);
4343
@@ -64,20 +64,71 @@ TEST(MapSharedShreddingContextTest, AdaptKCappedByKMax) {
6464 ASSERT_EQ (5 , next_k.at (" m" ));
6565}
6666
67- TEST (MapSharedShreddingContextTest, WindowMaxTracksLargest ) {
68- // K should use the max of all recent max_row_widths within the window .
67+ TEST (MapSharedShreddingContextTest, WindowP90UsesMaxWhenSamplesAreClose ) {
68+ // Small sample windows still use max because max and P90 are close .
6969 std::map<std::string, int32_t > field_to_k_max = {{" m" , 20 }};
7070 MapSharedShreddingContext context (field_to_k_max);
7171
7272 context.ReportFileStats (" m" , 3 );
7373 context.ReportFileStats (" m" , 7 );
7474 context.ReportFileStats (" m" , 5 );
7575
76- // max of {3, 7, 5} = 7, capped by K_max=20 → K=7.
7776 auto next_k = context.ComputeNextK ();
7877 ASSERT_EQ (7 , next_k.at (" m" ));
7978}
8079
80+ TEST (MapSharedShreddingContextTest, WindowP90IgnoresSingleFarOutlier) {
81+ std::map<std::string, int32_t > field_to_k_max = {{" m" , 2000 }};
82+ MapSharedShreddingContext context (field_to_k_max);
83+
84+ for (int32_t i = 0 ; i < 19 ; ++i) {
85+ context.ReportFileStats (" m" , 3 );
86+ }
87+ context.ReportFileStats (" m" , 1000 );
88+
89+ auto next_k = context.ComputeNextK ();
90+ ASSERT_EQ (3 , next_k.at (" m" ));
91+ }
92+
93+ TEST (MapSharedShreddingContextTest, WindowP90UsesMaxWithinAbsoluteSlack) {
94+ std::map<std::string, int32_t > field_to_k_max = {{" m" , 20 }};
95+ MapSharedShreddingContext context (field_to_k_max);
96+
97+ for (int32_t i = 0 ; i < 19 ; ++i) {
98+ context.ReportFileStats (" m" , 3 );
99+ }
100+ context.ReportFileStats (" m" , 7 );
101+
102+ auto next_k = context.ComputeNextK ();
103+ ASSERT_EQ (7 , next_k.at (" m" ));
104+ }
105+
106+ TEST (MapSharedShreddingContextTest, WindowP90UsesMaxWithinRelativeSlack) {
107+ std::map<std::string, int32_t > field_to_k_max = {{" m" , 200 }};
108+ MapSharedShreddingContext context (field_to_k_max);
109+
110+ for (int32_t i = 0 ; i < 19 ; ++i) {
111+ context.ReportFileStats (" m" , 100 );
112+ }
113+ context.ReportFileStats (" m" , 125 );
114+
115+ auto next_k = context.ComputeNextK ();
116+ ASSERT_EQ (125 , next_k.at (" m" ));
117+ }
118+
119+ TEST (MapSharedShreddingContextTest, WindowP90IgnoresMaxBeyondBothSlacks) {
120+ std::map<std::string, int32_t > field_to_k_max = {{" m" , 200 }};
121+ MapSharedShreddingContext context (field_to_k_max);
122+
123+ for (int32_t i = 0 ; i < 19 ; ++i) {
124+ context.ReportFileStats (" m" , 100 );
125+ }
126+ context.ReportFileStats (" m" , 130 );
127+
128+ auto next_k = context.ComputeNextK ();
129+ ASSERT_EQ (100 , next_k.at (" m" ));
130+ }
131+
81132TEST (MapSharedShreddingContextTest, MultipleColumnsIndependent) {
82133 // Each field adapts independently.
83134 std::map<std::string, int32_t > field_to_k_max = {{" tags" , 10 }, {" attrs" , 6 }};
@@ -101,8 +152,7 @@ TEST(MapSharedShreddingContextTest, MultipleColumnsIndependent) {
101152 context.ReportFileStats (" attrs" , 6 );
102153
103154 auto k3 = context.ComputeNextK ();
104- // tags: max(4,8)=8, capped by 10 → 8
105- // attrs: max(2,6)=6, capped by 6 → 6
155+ // tags and attrs are close sample windows, so adaptive width keeps max.
106156 ASSERT_EQ (8 , k3.at (" tags" ));
107157 ASSERT_EQ (6 , k3.at (" attrs" ));
108158}
@@ -116,7 +166,7 @@ TEST(MapSharedShreddingContextTest, GetShreddingColumnNames) {
116166}
117167
118168TEST (MapSharedShreddingContextTest, SlidingWindowEvictsOldEntries) {
119- // The window size is 100 . After filling 100 entries, adding one more
169+ // The window size is 20 . After filling 20 entries, adding one more
120170 // should evict the oldest. Verify that the evicted value no longer
121171 // affects ComputeNextK.
122172 std::map<std::string, int32_t > field_to_k_max = {{" m" , 256 }};
@@ -125,19 +175,19 @@ TEST(MapSharedShreddingContextTest, SlidingWindowEvictsOldEntries) {
125175 // Insert a large value as the first entry.
126176 context.ReportFileStats (" m" , 200 );
127177
128- // Fill the remaining 99 slots with small values.
129- for (int i = 0 ; i < 99 ; ++i) {
178+ // Fill the remaining 19 slots with small values.
179+ for (int32_t i = 0 ; i < 19 ; ++i) {
130180 context.ReportFileStats (" m" , 3 );
131181 }
132182
133- // Window = [200, 3, 3, ..., 3] (100 entries). Max = 200 .
183+ // Window = [200, 3, 3, ..., 3] (20 entries). P90 = 3, max is a far outlier .
134184 auto k_before = context.ComputeNextK ();
135- ASSERT_EQ (200 , k_before.at (" m" ));
185+ ASSERT_EQ (3 , k_before.at (" m" ));
136186
137187 // Push one more — evicts the 200.
138188 context.ReportFileStats (" m" , 5 );
139189
140- // Window = [3, 3, ..., 3, 5] (100 entries). Max = 5 .
190+ // Window = [3, 3, ..., 3, 5] (20 entries). Max is within the absolute slack .
141191 auto k_after = context.ComputeNextK ();
142192 ASSERT_EQ (5 , k_after.at (" m" ));
143193}
0 commit comments