| 738 | } |
| 739 | |
| 740 | ObjectStore::ObjectDatasetSnapshot ObjectStore::detachDataset(DatasetId dataset_id) { |
| 741 | // Same discipline as clearDataset, but MOVE each series' entries aside instead of |
| 742 | // dropping them. drainSeriesReaders before touching a series so no EntryTimestampsView |
| 743 | // dangles into the timestamp vector we move out. |
| 744 | std::unique_lock lock(store_mutex_); |
| 745 | ObjectDatasetSnapshot snapshot; |
| 746 | snapshot.dataset_id = dataset_id; |
| 747 | for (auto& [tid, series] : topics_) { |
| 748 | if (series->descriptor.dataset_id != dataset_id) { |
| 749 | continue; |
| 750 | } |
| 751 | snapshot.prior_object_topic_ids.push_back(tid); |
| 752 | drainSeriesReaders(*series); |
| 753 | ObjectDatasetSnapshot::SeriesSnapshot series_snapshot; |
| 754 | series_snapshot.entries = std::move(series->entries); |
| 755 | series_snapshot.entry_timestamps = std::move(series->entry_timestamps); |
| 756 | series_snapshot.budget = series->budget; |
| 757 | series_snapshot.memory_bytes = series->memory_bytes; |
| 758 | // Normalize the now-empty series in place (memory accounting + warm cache), |
| 759 | // keeping the ObjectTopicId registered — exactly like clearDataset. |
| 760 | clearEntriesLocked(*series); |
| 761 | snapshot.series.emplace(tid.id, std::move(series_snapshot)); |
| 762 | } |
| 763 | if (snapshot.prior_object_topic_ids.empty()) { |
| 764 | return snapshot; // unknown / empty dataset: `valid` stays false |
| 765 | } |
| 766 | snapshot.valid = true; |
| 767 | return snapshot; |
| 768 | } |
| 769 | |
| 770 | void ObjectStore::reattachDataset(DatasetId dataset_id, ObjectDatasetSnapshot&& snapshot) { |
| 771 | std::unique_lock lock(store_mutex_); |