blob: ba7bf657529377c1d9b2b48fbf6aa62171b56735 [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Alex Vakulenko57123b22014-10-28 13:50:16 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Stefan Sauer2d16dfa2015-09-25 17:08:35 +02005#include "src/states/state_change_queue.h"
Alex Vakulenko57123b22014-10-28 13:50:16 -07006
Alex Deymof6cbe322014-11-10 19:55:35 -08007#include <base/logging.h>
Alex Vakulenko8a05beb2015-11-24 17:13:20 -08008#include <base/values.h>
Alex Deymof6cbe322014-11-10 19:55:35 -08009
Vitaly Bukab6f015a2015-07-09 14:59:23 -070010namespace weave {
Alex Vakulenko57123b22014-10-28 13:50:16 -070011
12StateChangeQueue::StateChangeQueue(size_t max_queue_size)
13 : max_queue_size_(max_queue_size) {
Mike Frysinger42e3a722014-11-15 06:48:08 -050014 CHECK_GT(max_queue_size_, 0U) << "Max queue size must not be zero";
Alex Vakulenko57123b22014-10-28 13:50:16 -070015}
16
Alex Vakulenko7d669212015-11-23 16:05:24 -080017bool StateChangeQueue::NotifyPropertiesUpdated(
18 base::Time timestamp,
19 std::unique_ptr<base::DictionaryValue> changed_properties) {
Vitaly Buka70b697f2015-07-28 14:36:29 -070020 auto& stored_changes = state_changes_[timestamp];
21 // Merge the old property set.
Alex Vakulenko7d669212015-11-23 16:05:24 -080022 if (stored_changes)
23 stored_changes->MergeDictionary(changed_properties.get());
24 else
25 stored_changes = std::move(changed_properties);
Vitaly Buka70b697f2015-07-28 14:36:29 -070026
Alex Vakulenko57123b22014-10-28 13:50:16 -070027 while (state_changes_.size() > max_queue_size_) {
28 // Queue is full.
29 // Merge the two oldest records into one. The merge strategy is:
30 // - Move non-existent properties from element [old] to [new].
31 // - If both [old] and [new] specify the same property,
32 // keep the value of [new].
33 // - Keep the timestamp of [new].
34 auto element_old = state_changes_.begin();
35 auto element_new = std::next(element_old);
36 // This will skip elements that exist in both [old] and [new].
Alex Vakulenko7d669212015-11-23 16:05:24 -080037 element_old->second->MergeDictionary(element_new->second.get());
38 std::swap(element_old->second, element_new->second);
Alex Vakulenko57123b22014-10-28 13:50:16 -070039 state_changes_.erase(element_old);
40 }
Alex Vakulenkoe7a70072015-06-25 11:36:07 -070041 ++last_change_id_;
Alex Vakulenko57123b22014-10-28 13:50:16 -070042 return true;
43}
44
45std::vector<StateChange> StateChangeQueue::GetAndClearRecordedStateChanges() {
Alex Vakulenkoff73cf22014-10-29 09:53:52 -070046 std::vector<StateChange> changes;
47 changes.reserve(state_changes_.size());
Alex Vakulenko7d669212015-11-23 16:05:24 -080048 for (auto& pair : state_changes_) {
49 changes.push_back(StateChange{pair.first, std::move(pair.second)});
Alex Vakulenkoff73cf22014-10-29 09:53:52 -070050 }
51 state_changes_.clear();
52 return changes;
Alex Vakulenko57123b22014-10-28 13:50:16 -070053}
54
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070055StateChangeQueueInterface::Token StateChangeQueue::AddOnStateUpdatedCallback(
56 const base::Callback<void(UpdateID)>& callback) {
57 if (state_changes_.empty())
58 callback.Run(last_change_id_);
59 return Token{callbacks_.Add(callback).release()};
60}
61
62void StateChangeQueue::NotifyStateUpdatedOnServer(UpdateID update_id) {
63 callbacks_.Notify(update_id);
64}
65
Vitaly Bukab6f015a2015-07-09 14:59:23 -070066} // namespace weave