blob: 74ac682045c1940011a224fd53c4c95a8f60d4d0 [file] [log] [blame]
Alex Vakulenko57123b22014-10-28 13:50:16 -07001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alex Vakulenko57123b22014-10-28 13:50:16 -07005#include "buffet/states/state_change_queue.h"
6
Alex Deymof6cbe322014-11-10 19:55:35 -08007#include <base/logging.h>
8
Alex Vakulenko57123b22014-10-28 13:50:16 -07009namespace buffet {
10
11StateChangeQueue::StateChangeQueue(size_t max_queue_size)
12 : max_queue_size_(max_queue_size) {
Mike Frysinger42e3a722014-11-15 06:48:08 -050013 CHECK_GT(max_queue_size_, 0U) << "Max queue size must not be zero";
Alex Vakulenko57123b22014-10-28 13:50:16 -070014}
15
Alex Vakulenkoff73cf22014-10-29 09:53:52 -070016bool StateChangeQueue::NotifyPropertiesUpdated(
17 base::Time timestamp,
Anton Muhin01829452014-11-21 02:16:04 +040018 native_types::Object changed_properties) {
Alex Vakulenko57123b22014-10-28 13:50:16 -070019 DCHECK(thread_checker_.CalledOnValidThread());
Alex Vakulenkoff73cf22014-10-29 09:53:52 -070020 auto it = state_changes_.lower_bound(timestamp);
21 if (it == state_changes_.end() || it->first != timestamp) {
22 // This timestamp doesn't exist. Insert a new element.
23 state_changes_.emplace_hint(it, timestamp, std::move(changed_properties));
24 } else {
25 // Merge the old property set and the new one.
26 // For properties that exist in both old and new property sets, keep the
27 // new values.
28 changed_properties.insert(it->second.begin(), it->second.end());
29 it->second = std::move(changed_properties);
30 }
Alex Vakulenko57123b22014-10-28 13:50:16 -070031 while (state_changes_.size() > max_queue_size_) {
32 // Queue is full.
33 // Merge the two oldest records into one. The merge strategy is:
34 // - Move non-existent properties from element [old] to [new].
35 // - If both [old] and [new] specify the same property,
36 // keep the value of [new].
37 // - Keep the timestamp of [new].
38 auto element_old = state_changes_.begin();
39 auto element_new = std::next(element_old);
40 // This will skip elements that exist in both [old] and [new].
Alex Vakulenkoff73cf22014-10-29 09:53:52 -070041 element_new->second.insert(element_old->second.begin(),
42 element_old->second.end());
Alex Vakulenko57123b22014-10-28 13:50:16 -070043 state_changes_.erase(element_old);
44 }
45 return true;
46}
47
48std::vector<StateChange> StateChangeQueue::GetAndClearRecordedStateChanges() {
49 DCHECK(thread_checker_.CalledOnValidThread());
Alex Vakulenkoff73cf22014-10-29 09:53:52 -070050 std::vector<StateChange> changes;
51 changes.reserve(state_changes_.size());
52 for (const auto& pair : state_changes_) {
53 changes.emplace_back(pair.first, std::move(pair.second));
54 }
55 state_changes_.clear();
56 return changes;
Alex Vakulenko57123b22014-10-28 13:50:16 -070057}
58
59} // namespace buffet