@@ -1409,78 +1409,107 @@ error_code RdbSaver::Impl::FlushSerializer() {
14091409 return ec;
14101410}
14111411
1412- RdbSaver::GlobalData RdbSaver::GetGlobalData (const Service* service) {
1412+ namespace {
1413+
1414+ // Collect search index definitions. If as_json is true, collects JSON with HNSW metadata
1415+ // and synonyms (for summary file). Otherwise collects simple restore commands (for per-shard).
1416+ void CollectSearchIndices ([[maybe_unused]] EngineShard* shard,
1417+ [[maybe_unused]] StringVec* search_indices,
1418+ [[maybe_unused]] StringVec* search_synonyms,
1419+ [[maybe_unused]] bool is_summary) {
1420+ #ifdef WITH_SEARCH
1421+ auto * indices = shard->search_indices ();
1422+ for (const auto & index_name : indices->GetIndexNames ()) {
1423+ auto * index = indices->GetIndex (index_name);
1424+ auto index_info = index->GetInfo ();
1425+
1426+ if (!is_summary) {
1427+ std::string restore_cmd = absl::StrCat (index_name, " " , index_info.BuildRestoreCommand ());
1428+ search_indices->emplace_back (std::move (restore_cmd));
1429+ continue ;
1430+ }
1431+
1432+ // Collect HNSW metadata for vector field (first one found)
1433+ for (const auto & [fident, finfo] : index_info.base_index .schema .fields ) {
1434+ if (finfo.type == search::SchemaField::VECTOR &&
1435+ !(finfo.flags & search::SchemaField::NOINDEX)) {
1436+ if (auto hnsw_index = GlobalHnswIndexRegistry::Instance ().Get (index_name, finfo.short_name );
1437+ hnsw_index) {
1438+ index_info.hnsw_metadata = hnsw_index->GetMetadata ();
1439+ break ;
1440+ }
1441+ }
1442+ }
1443+
1444+ // Save index definition as JSON with HNSW metadata
1445+ TmpJson index_json;
1446+ index_json[" name" ] = index_name;
1447+ index_json[" cmd" ] = index_info.BuildRestoreCommand ();
1448+
1449+ if (index_info.hnsw_metadata .has_value ()) {
1450+ const auto & meta = index_info.hnsw_metadata .value ();
1451+ TmpJson hnsw_meta;
1452+ hnsw_meta[" max_elements" ] = meta.max_elements ;
1453+ hnsw_meta[" cur_element_count" ] = meta.cur_element_count ;
1454+ hnsw_meta[" maxlevel" ] = meta.maxlevel ;
1455+ hnsw_meta[" enterpoint_node" ] = meta.enterpoint_node ;
1456+ hnsw_meta[" M" ] = meta.M ;
1457+ hnsw_meta[" maxM" ] = meta.maxM ;
1458+ hnsw_meta[" maxM0" ] = meta.maxM0 ;
1459+ hnsw_meta[" ef_construction" ] = meta.ef_construction ;
1460+ hnsw_meta[" mult" ] = meta.mult ;
1461+ index_json[" hnsw_metadata" ] = std::move (hnsw_meta);
1462+ }
1463+
1464+ search_indices->emplace_back (index_json.to_string ());
1465+
1466+ // Save synonym groups
1467+ const auto & synonym_groups = index->GetSynonyms ().GetGroups ();
1468+ for (const auto & [group_id, terms] : synonym_groups) {
1469+ if (!terms.empty ()) {
1470+ std::string syn_cmd =
1471+ absl::StrCat (index_name, " " , group_id, " " , absl::StrJoin (terms, " " ));
1472+ search_synonyms->emplace_back (std::move (syn_cmd));
1473+ }
1474+ }
1475+ }
1476+ #endif
1477+ }
1478+
1479+ } // namespace
1480+
1481+ RdbSaver::GlobalData RdbSaver::GetGlobalData (const Service* service, bool is_summary) {
14131482 StringVec script_bodies, search_indices, search_synonyms;
1483+ size_t table_mem_result = 0 ;
14141484
14151485 {
1486+ // For summary file: collect all global data
14161487 auto scripts = service->script_mgr ()->GetAll ();
14171488 script_bodies.reserve (scripts.size ());
14181489 for (auto & [sha, data] : scripts)
14191490 script_bodies.push_back (std::move (data.body ));
14201491 }
14211492
1493+ if (!is_summary) {
1494+ shard_set->RunBriefInParallel ([&](EngineShard* shard) {
1495+ if (shard->shard_id () == 0 )
1496+ CollectSearchIndices (shard, &search_indices, &search_synonyms, is_summary);
1497+ });
1498+ return RdbSaver::GlobalData{std::move (script_bodies), std::move (search_indices),
1499+ std::move (search_synonyms), table_mem_result};
1500+ }
1501+
14221502 atomic<size_t > table_mem{0 };
14231503 shard_set->RunBriefInParallel ([&](EngineShard* shard) {
1424- #ifdef WITH_SEARCH
1425- if (shard->shard_id () == 0 ) {
1426- auto * indices = shard->search_indices ();
1427- for (const auto & index_name : indices->GetIndexNames ()) {
1428- auto * index = indices->GetIndex (index_name);
1429- auto index_info = index->GetInfo ();
1430-
1431- // Collect HNSW metadata for vector field (first one found)
1432- for (const auto & [fident, finfo] : index_info.base_index .schema .fields ) {
1433- if (finfo.type == search::SchemaField::VECTOR &&
1434- !(finfo.flags & search::SchemaField::NOINDEX)) {
1435- if (auto hnsw_index =
1436- GlobalHnswIndexRegistry::Instance ().Get (index_name, finfo.short_name );
1437- hnsw_index) {
1438- index_info.hnsw_metadata = hnsw_index->GetMetadata ();
1439- break ; // Only store first HNSW index metadata
1440- }
1441- }
1442- }
1443-
1444- // Save index definition as JSON with HNSW metadata
1445- TmpJson index_json;
1446- index_json[" name" ] = index_name;
1447- index_json[" cmd" ] = index_info.BuildRestoreCommand ();
1448-
1449- if (index_info.hnsw_metadata .has_value ()) {
1450- const auto & meta = index_info.hnsw_metadata .value ();
1451- TmpJson hnsw_meta;
1452- hnsw_meta[" max_elements" ] = meta.max_elements ;
1453- hnsw_meta[" cur_element_count" ] = meta.cur_element_count ;
1454- hnsw_meta[" maxlevel" ] = meta.maxlevel ;
1455- hnsw_meta[" enterpoint_node" ] = meta.enterpoint_node ;
1456- hnsw_meta[" M" ] = meta.M ;
1457- hnsw_meta[" maxM" ] = meta.maxM ;
1458- hnsw_meta[" maxM0" ] = meta.maxM0 ;
1459- hnsw_meta[" ef_construction" ] = meta.ef_construction ;
1460- hnsw_meta[" mult" ] = meta.mult ;
1461- index_json[" hnsw_metadata" ] = std::move (hnsw_meta);
1462- }
1504+ shard_set->RunBriefInParallel ([&](EngineShard* shard) {
1505+ if (shard->shard_id () == 0 )
1506+ CollectSearchIndices (shard, &search_indices, &search_synonyms, is_summary);
1507+ });
14631508
1464- search_indices.emplace_back (index_json.to_string ());
1465-
1466- // Save synonym groups to separate vector
1467- const auto & synonym_groups = index->GetSynonyms ().GetGroups ();
1468- for (const auto & [group_id, terms] : synonym_groups) {
1469- if (!terms.empty ()) {
1470- // Format: "index_name group_id term1 term2 term3"
1471- std::string syn_cmd =
1472- absl::StrCat (index_name, " " , group_id, " " , absl::StrJoin (terms, " " ));
1473- search_synonyms.emplace_back (std::move (syn_cmd));
1474- }
1475- }
1476- }
1477- }
1478- #endif
14791509 auto & db_slice = namespaces->GetDefaultNamespace ().GetDbSlice (shard->shard_id ());
14801510 size_t shard_table_mem = 0 ;
14811511 for (size_t db_id = 0 ; db_id < db_slice.db_array_size (); ++db_id) {
14821512 auto * db_table = db_slice.GetDBTable (db_id);
1483-
14841513 if (db_table) {
14851514 shard_table_mem += db_table->table_memory ();
14861515 }
@@ -1625,12 +1654,11 @@ error_code RdbSaver::SaveAux(const GlobalData& glob_state) {
16251654 if (!glob_state.search_indices .empty ())
16261655 LOG (WARNING) << " Dragonfly search index data is incompatible with the RDB format" ;
16271656 } else {
1628- // Search index definitions are not tied to shards and are saved in the summary file
1629- DCHECK (save_mode_ != SaveMode::SINGLE_SHARD || glob_state.search_indices .empty ());
1657+ // Search index definitions (JSON for summary, simple restore cmd for per-shard)
16301658 for (const string& s : glob_state.search_indices )
16311659 RETURN_ON_ERR (impl_->SaveAuxFieldStrStr (" search-index" , s));
16321660
1633- // Save synonyms in separate aux fields
1661+ // Save synonyms only in summary file
16341662 DCHECK (save_mode_ != SaveMode::SINGLE_SHARD || glob_state.search_synonyms .empty ());
16351663 for (const string& s : glob_state.search_synonyms )
16361664 RETURN_ON_ERR (impl_->SaveAuxFieldStrStr (" search-synonyms" , s));
0 commit comments