buffet: Fix issues in StateChangeQueue
Addressed additional code review issues brought after the original
code has been published.
- NotifyPropertiesUpdated() now takes timestamp and property set
as separate parameters to simplify implementation of StateManager.
- StateChangeQueue::max_queue_size_ is made 'const'
- StateChangeQueue now maintains a time-to-event map instead of
a vector of StateChange. This allows to keep the events sorted
by time stamp. Also adding discrete events with the same time stamp
coalesces the property changes.
- added a unit test for coalescing property set changes based on
the timestamp.
BUG=None
TEST=FEATURES=test emerge-link buffet
Change-Id: I309816d1f040558620fa68a844b05251d0e4319b
Reviewed-on: https://chromium-review.googlesource.com/226300
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Reviewed-by: Anton Muhin <antonm@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/states/state_change_queue.cc b/buffet/states/state_change_queue.cc
index a288c0f..663d799 100644
--- a/buffet/states/state_change_queue.cc
+++ b/buffet/states/state_change_queue.cc
@@ -13,9 +13,21 @@
CHECK_GT(max_queue_size_, 0) << "Max queue size must not be zero";
}
-bool StateChangeQueue::NotifyPropertiesUpdated(const StateChange& change) {
+bool StateChangeQueue::NotifyPropertiesUpdated(
+ base::Time timestamp,
+ chromeos::VariantDictionary changed_properties) {
DCHECK(thread_checker_.CalledOnValidThread());
- state_changes_.push_back(change);
+ auto it = state_changes_.lower_bound(timestamp);
+ if (it == state_changes_.end() || it->first != timestamp) {
+ // This timestamp doesn't exist. Insert a new element.
+ state_changes_.emplace_hint(it, timestamp, std::move(changed_properties));
+ } else {
+ // Merge the old property set and the new one.
+ // For properties that exist in both old and new property sets, keep the
+ // new values.
+ changed_properties.insert(it->second.begin(), it->second.end());
+ it->second = std::move(changed_properties);
+ }
while (state_changes_.size() > max_queue_size_) {
// Queue is full.
// Merge the two oldest records into one. The merge strategy is:
@@ -26,8 +38,8 @@
auto element_old = state_changes_.begin();
auto element_new = std::next(element_old);
// This will skip elements that exist in both [old] and [new].
- element_new->property_set.insert(element_old->property_set.begin(),
- element_old->property_set.end());
+ element_new->second.insert(element_old->second.begin(),
+ element_old->second.end());
state_changes_.erase(element_old);
}
return true;
@@ -35,8 +47,13 @@
std::vector<StateChange> StateChangeQueue::GetAndClearRecordedStateChanges() {
DCHECK(thread_checker_.CalledOnValidThread());
- // Return the accumulated state changes and clear the current queue.
- return std::move(state_changes_);
+ std::vector<StateChange> changes;
+ changes.reserve(state_changes_.size());
+ for (const auto& pair : state_changes_) {
+ changes.emplace_back(pair.first, std::move(pair.second));
+ }
+ state_changes_.clear();
+ return changes;
}
} // namespace buffet