@@ -2761,6 +2761,9 @@ TYPED_TEST(HNSWTieredIndexTest, testInfo) {
27612761 EXPECT_EQ (info.tieredInfo .backgroundIndexing , false );
27622762 EXPECT_EQ (info.tieredInfo .bufferLimit , 1000 );
27632763 EXPECT_EQ (info.tieredInfo .specificTieredBackendInfo .hnswTieredInfo .pendingSwapJobsThreshold , 1 );
2764+ // Verify new tiered-specific stats
2765+ EXPECT_EQ (stats.flatBufferSize , 0 );
2766+ EXPECT_EQ (stats.directHNSWInsertions , 0 );
27642767
27652768 // Validate that Static info returns the right restricted info as well.
27662769 VecSimIndexBasicInfo s_info = VecSimIndex_BasicInfo (tiered_index);
@@ -2787,6 +2790,9 @@ TYPED_TEST(HNSWTieredIndexTest, testInfo) {
27872790 info.tieredInfo .frontendCommonInfo .memory );
27882791 EXPECT_EQ (info.commonInfo .memory , stats.memory );
27892792 EXPECT_EQ (info.tieredInfo .backgroundIndexing , true );
2793+ // Vector is in flat buffer, no direct insertions yet
2794+ EXPECT_EQ (stats.flatBufferSize , 1 );
2795+ EXPECT_EQ (stats.directHNSWInsertions , 0 );
27902796
27912797 mock_thread_pool.thread_iteration ();
27922798 info = tiered_index->debugInfo ();
@@ -2803,6 +2809,9 @@ TYPED_TEST(HNSWTieredIndexTest, testInfo) {
28032809 info.tieredInfo .frontendCommonInfo .memory );
28042810 EXPECT_EQ (info.commonInfo .memory , stats.memory );
28052811 EXPECT_EQ (info.tieredInfo .backgroundIndexing , false );
2812+ // Vector moved from flat buffer to HNSW by background thread
2813+ EXPECT_EQ (stats.flatBufferSize , 0 );
2814+ EXPECT_EQ (stats.directHNSWInsertions , 0 );
28062815
28072816 if (TypeParam::isMulti ()) {
28082817 GenerateAndAddVector<TEST_DATA_T>(tiered_index, dim, 1 , 1 );
@@ -2839,6 +2848,74 @@ TYPED_TEST(HNSWTieredIndexTest, testInfo) {
28392848 EXPECT_EQ (info.tieredInfo .backgroundIndexing , false );
28402849}
28412850
2851+ TYPED_TEST (HNSWTieredIndexTest, testDirectHNSWInsertionsStats) {
2852+ // Test that directHNSWInsertions counter is incremented when flat buffer is full.
2853+ size_t dim = 4 ;
2854+ size_t buffer_limit = 5 ;
2855+ HNSWParams params = {.type = TypeParam::get_index_type (),
2856+ .dim = dim,
2857+ .metric = VecSimMetric_L2,
2858+ .multi = TypeParam::isMulti ()};
2859+ VecSimParams hnsw_params = CreateParams (params);
2860+ auto mock_thread_pool = tieredIndexMock ();
2861+
2862+ // Create index with small buffer limit
2863+ auto *tiered_index =
2864+ this ->CreateTieredHNSWIndex (hnsw_params, mock_thread_pool, 1 , buffer_limit);
2865+
2866+ // Fill the flat buffer
2867+ for (size_t i = 0 ; i < buffer_limit; i++) {
2868+ GenerateAndAddVector<TEST_DATA_T>(tiered_index, dim, i, i);
2869+ }
2870+
2871+ VecSimIndexStatsInfo stats = tiered_index->statisticInfo ();
2872+ EXPECT_EQ (stats.flatBufferSize , buffer_limit);
2873+ EXPECT_EQ (stats.directHNSWInsertions , 0 );
2874+
2875+ // Add more vectors - these should go directly to HNSW
2876+ size_t extra_vectors = 3 ;
2877+ for (size_t i = buffer_limit; i < buffer_limit + extra_vectors; i++) {
2878+ GenerateAndAddVector<TEST_DATA_T>(tiered_index, dim, i, i);
2879+ }
2880+
2881+ stats = tiered_index->statisticInfo ();
2882+ EXPECT_EQ (stats.flatBufferSize , buffer_limit);
2883+ EXPECT_EQ (stats.directHNSWInsertions , extra_vectors);
2884+
2885+ // Drain the flat buffer by starting threads and waiting for them to finish
2886+ mock_thread_pool.init_threads ();
2887+ mock_thread_pool.thread_pool_join ();
2888+
2889+ stats = tiered_index->statisticInfo ();
2890+ EXPECT_EQ (stats.flatBufferSize , 0 );
2891+ // Direct insertions counter should be preserved
2892+ EXPECT_EQ (stats.directHNSWInsertions , extra_vectors);
2893+
2894+ // Test write-in-place mode: vectors should go directly to HNSW even when buffer is not full
2895+ VecSim_SetWriteMode (VecSim_WriteInPlace);
2896+
2897+ size_t write_in_place_vectors = 4 ;
2898+ size_t label_offset = buffer_limit + extra_vectors;
2899+ for (size_t i = 0 ; i < write_in_place_vectors; i++) {
2900+ GenerateAndAddVector<TEST_DATA_T>(tiered_index, dim, label_offset + i, label_offset + i);
2901+ }
2902+
2903+ stats = tiered_index->statisticInfo ();
2904+ // Flat buffer should still be empty (vectors went directly to HNSW)
2905+ EXPECT_EQ (stats.flatBufferSize , 0 );
2906+ // Direct insertions counter should include the write-in-place vectors
2907+ EXPECT_EQ (stats.directHNSWInsertions , extra_vectors + write_in_place_vectors);
2908+
2909+ // Verify all vectors are in the backend index
2910+ VecSimIndexDebugInfo info = tiered_index->debugInfo ();
2911+ EXPECT_EQ (info.tieredInfo .backendCommonInfo .indexSize ,
2912+ buffer_limit + extra_vectors + write_in_place_vectors);
2913+ EXPECT_EQ (info.tieredInfo .frontendCommonInfo .indexSize , 0 );
2914+
2915+ // Reset to async mode
2916+ VecSim_SetWriteMode (VecSim_WriteAsync);
2917+ }
2918+
28422919TYPED_TEST (HNSWTieredIndexTest, testInfoIterator) {
28432920 // Create TieredHNSW index instance with a mock queue.
28442921 size_t dim = 4 ;
0 commit comments