11#include " change_notifier.hpp"
22
33#include < launchdarkly/signals/boost_signal_connection.hpp>
4+
45#include < mutex>
6+ #include < utility>
7+ #include < variant>
58
69namespace launchdarkly ::server_side::data_components {
710
11+ namespace {
12+
13+ template <class ... Ts>
14+ struct overloaded : Ts... {
15+ using Ts::operator ()...;
16+ };
17+ template <class ... Ts>
18+ overloaded (Ts...) -> overloaded<Ts...>;
19+
20+ } // namespace
21+
822std::unique_ptr<IConnection> ChangeNotifier::OnFlagChange (
923 ChangeHandler handler) {
1024 std::lock_guard lock{signal_mutex_};
@@ -55,6 +69,79 @@ void ChangeNotifier::Upsert(std::string const& key,
5569 std::move (segment));
5670}
5771
72+ void ChangeNotifier::Apply (
73+ data_model::ChangeSet<data_interfaces::ChangeSetData> change_set) {
74+ if (change_set.type == data_model::ChangeSetType::kNone ) {
75+ return ;
76+ }
77+
78+ // Compute changed dependencies before passing the changeset to the sink.
79+ std::optional<DependencySet> change_notifications;
80+ if (HasListeners ()) {
81+ DependencySet affected;
82+ if (change_set.type == data_model::ChangeSetType::kFull ) {
83+ // Group items by kind so the existing per-kind diff helper can
84+ // compare the new state to the existing store contents.
85+ Collection<data_model::Flag> new_flags;
86+ Collection<data_model::Segment> new_segments;
87+ for (auto const & change : change_set.data ) {
88+ std::visit (
89+ overloaded{
90+ [&](data_model::ItemDescriptor<data_model::Flag> const &
91+ f) { new_flags.emplace (change.key , f); },
92+ [&](data_model::ItemDescriptor<
93+ data_model::Segment> const & s) {
94+ new_segments.emplace (change.key , s);
95+ },
96+ },
97+ change.object );
98+ }
99+ CalculateChanges (DataKind::kFlag , source_.AllFlags (), new_flags,
100+ affected);
101+ CalculateChanges (DataKind::kSegment , source_.AllSegments (),
102+ new_segments, affected);
103+ } else {
104+ // Partial: every item in the changeset is treated as a change;
105+ // no version comparison.
106+ for (auto const & change : change_set.data ) {
107+ std::visit (overloaded{
108+ [&](data_model::ItemDescriptor<
109+ data_model::Flag> const &) {
110+ dependency_tracker_.CalculateChanges (
111+ DataKind::kFlag , change.key , affected);
112+ },
113+ [&](data_model::ItemDescriptor<
114+ data_model::Segment> const &) {
115+ dependency_tracker_.CalculateChanges (
116+ DataKind::kSegment , change.key ,
117+ affected);
118+ },
119+ },
120+ change.object );
121+ }
122+ }
123+ change_notifications = std::move (affected);
124+ }
125+
126+ // Update the dependency tracker.
127+ if (change_set.type == data_model::ChangeSetType::kFull ) {
128+ dependency_tracker_.Clear ();
129+ }
130+ for (auto const & change : change_set.data ) {
131+ std::visit (
132+ [&](auto const & descriptor) {
133+ dependency_tracker_.UpdateDependencies (change.key , descriptor);
134+ },
135+ change.object );
136+ }
137+
138+ sink_.Apply (std::move (change_set));
139+
140+ if (change_notifications) {
141+ NotifyChanges (std::move (*change_notifications));
142+ }
143+ }
144+
58145bool ChangeNotifier::HasListeners () const {
59146 std::lock_guard lock{signal_mutex_};
60147 return !signals_.empty ();
@@ -69,7 +156,7 @@ void ChangeNotifier::NotifyChanges(DependencySet changes) {
69156 }
70157}
71158
72- ChangeNotifier::ChangeNotifier (IDestination & sink,
159+ ChangeNotifier::ChangeNotifier (data_interfaces::ITransactionalDestination & sink,
73160 data_interfaces::IStore const & source)
74161 : sink_(sink), source_(source) {}
75162
0 commit comments