Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium 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 | |
| 5 #ifndef BLIMP_NET_HELIUM_SYNCABLE_H_ | |
| 6 #define BLIMP_NET_HELIUM_SYNCABLE_H_ | |
| 7 | |
| 8 #include <stdint.h> | |
| 9 #include <memory> | |
| 10 | |
| 11 #include "base/callback.h" | |
| 12 #include "base/macros.h" | |
| 13 #include "blimp/net/helium/vector_clock.h" | |
| 14 | |
| 15 namespace blimp { | |
| 16 | |
| 17 namespace proto { | |
| 18 class ChangesetMessage; | |
| 19 } | |
| 20 | |
| 21 // Syncable is a base class interface that is used for both SyncableObject and | |
| 22 // SyncableMember classes. | |
| 23 // | |
| 24 // Syncable is something that supports creating and restoring Changesets. | |
| 25 // Objects exchange Changesets between the client and server to keep | |
| 26 // their peer counterparts eventually synchronized. | |
| 27 // | |
| 28 // 1. Mapping: There is a one-to-one relationship between instances on the | |
| 29 // client and instances on the engine. | |
| 30 // 2. Consistency: The values stored in client-engine pairs should eventually be | |
| 31 // equal. | |
| 32 // | |
| 33 // The main difference is that SyncableObject owns its lifetime, whereas | |
| 34 // SyncableMember depends on its SyncableObject parent. | |
| 35 // | |
| 36 // An example for GeoLocation would be: | |
| 37 // GeoLocation : SyncableObject { | |
| 38 // * Frequency : SyncableMember | |
| 39 // * Position : SyncableMember | |
| 40 // } | |
| 41 // | |
| 42 // VectorClocks from a SyncableMember can be compared with the VectorClock from | |
| 43 // the SyncableObject. This reduces the amount of state that needs to be kept. | |
| 44 | |
| 45 template <class ChangesetType> | |
| 46 class Syncable { | |
| 47 public: | |
| 48 using CreateChangesetCallback = | |
| 49 base::Callback<void(std::unique_ptr<ChangesetType> changeset)>; | |
| 50 | |
| 51 virtual ~Syncable() {} | |
| 52 | |
| 53 // Constructs a changeset between the |from| revision and its current state. | |
| 54 // The Sync layer will encapsulate the changeset with details since |from|, | |
| 55 // but the Object is responsible for including any revision information | |
| 56 // additional to that expressed by the VectorClocks, that is necessary to | |
| 57 // detect and resolve conflicts. | |
| 58 // The computed changeset is returned asynchronously as a return parameter. | |
| 59 virtual std::unique_ptr<ChangesetType> CreateChangesetToCurrent( | |
| 60 const VectorClock& from) = 0; | |
| 61 | |
| 62 // Asynchronous version of the CreateChangesetToCurrent. | |
| 63 // Subclasses are free to implement a more optimal implementation, for example | |
| 64 // if a SyncableObject contains |n| SyncableMembers, it can ask to create | |
| 65 // the changeset asynchronously from all the SyncableMembers instead of using | |
| 66 // the serialized version. | |
| 67 // The closure |response_callback| its called with the changeset when its | |
| 68 // ready. | |
| 69 virtual void CreateChangesetToCurrentAsync( | |
| 70 const VectorClock& from, | |
| 71 CreateChangesetCallback response_callback) { | |
| 72 std::unique_ptr<ChangesetType> changeset = CreateChangesetToCurrent(from); | |
| 73 response_callback.Run(std::move(changeset)); | |
| 74 } | |
| 75 | |
| 76 // Applies a |changeset| given as parameter to the contents of the | |
| 77 // Syncable. | |
| 78 // The VectorClocks |from| and |to| can be used to detect and resolve | |
| 79 // concurrent change conflicts. | |
| 80 // The closure |done| its called when the state is applied. | |
| 81 virtual void ApplyChangeset(const VectorClock& from, | |
|
Kevin M
2016/10/05 18:42:45
I'm not very comfortable with exposing the sync an
| |
| 82 const VectorClock& to, | |
| 83 std::unique_ptr<ChangesetType> changeset) = 0; | |
| 84 | |
| 85 // Asynchronous version of ApplyChangeset. | |
| 86 // Subclasses are free to implement a more optimal implementation for example | |
| 87 // if a SyncableObject contains |n| SyncableMembers, it can ask to apply | |
| 88 // the changeset asynchronously from all the SyncableMembers instead of using | |
| 89 // the serialized version. | |
| 90 // The closure |done| its called when the changeset is applied. | |
| 91 virtual void ApplyChangesetAsync(const VectorClock& from, | |
| 92 const VectorClock& to, | |
| 93 std::unique_ptr<ChangesetType> changeset, | |
| 94 const base::Closure& done) { | |
| 95 ApplyChangeset(from, to, std::move(changeset)); | |
| 96 done.Run(); | |
| 97 } | |
| 98 | |
| 99 // Gives a chance for the Syncable to delete any old data previous to the | |
| 100 // |checkpoint|. This is a pretty important method that will remove some | |
| 101 // memory pressure for example from the UniqueSet CRDTs. They need to keep | |
| 102 // a growing list of added/removed elements over time. With this checkpoint | |
| 103 // info they can delete those elements prior to the vector clock specified in | |
| 104 // |checkpoint|. | |
| 105 virtual void ReleaseCheckpointsBefore(const VectorClock& checkpoint) = 0; | |
| 106 }; | |
| 107 | |
| 108 class SyncableObject : public Syncable<proto::ChangesetMessage> { | |
| 109 public: | |
| 110 explicit SyncableObject(const VectorClock& clock); | |
| 111 ~SyncableObject() override {} | |
| 112 | |
| 113 const VectorClock& clock() const { return clock_; } | |
| 114 | |
| 115 VectorClock* mutable_clock() { return &clock_; } | |
| 116 | |
| 117 protected: | |
| 118 // The clock is needed in order for the |SyncableMember| objects whenever | |
| 119 // they modify their state they update their |last_modified_| value. | |
| 120 // The rationale here is use a "global" per SyncableObject clock which makes | |
| 121 // state management a lot simpler. | |
| 122 VectorClock clock_; | |
| 123 | |
| 124 private: | |
| 125 DISALLOW_COPY_AND_ASSIGN(SyncableObject); | |
| 126 }; | |
| 127 | |
| 128 template <class ChangesetType> | |
| 129 class SyncableMember : public Syncable<ChangesetType> { | |
| 130 public: | |
| 131 explicit SyncableMember(SyncableObject* parent); | |
| 132 ~SyncableMember() override {} | |
| 133 | |
| 134 // Returns true if the object have been modified since |from|. | |
| 135 virtual bool ModifiedSince(const VectorClock& from) = 0; | |
| 136 | |
| 137 protected: | |
| 138 // Increments the parent clock and returns the new value. Should be used | |
| 139 // whenever a SyncableMember updates its state. | |
| 140 VectorClock IncrementParentClock(); | |
|
perumaal
2016/10/05 20:42:49
Why is there an IncrementParentClock / parent_cloc
| |
| 141 | |
| 142 // Returns the current value of the vector clock of the parent object (aka | |
| 143 // SyncableObject). | |
| 144 const VectorClock& parent_clock() const; | |
| 145 | |
| 146 private: | |
| 147 SyncableObject* parent_; | |
| 148 DISALLOW_COPY_AND_ASSIGN(SyncableMember); | |
| 149 }; | |
| 150 | |
| 151 SyncableObject::SyncableObject(const VectorClock& clock) : clock_(clock) {} | |
| 152 | |
| 153 template <class ChangesetType> | |
| 154 SyncableMember<ChangesetType>::SyncableMember(SyncableObject* parent) | |
| 155 : parent_(parent) {} | |
| 156 | |
| 157 template <class ChangesetType> | |
| 158 VectorClock SyncableMember<ChangesetType>::IncrementParentClock() { | |
| 159 parent_->mutable_clock()->IncrementLocal(); | |
| 160 return parent_->clock(); | |
| 161 } | |
| 162 | |
| 163 template <class ChangesetType> | |
| 164 const VectorClock& SyncableMember<ChangesetType>::parent_clock() const { | |
| 165 return parent_->clock(); | |
| 166 } | |
| 167 | |
| 168 } // namespace blimp | |
| 169 | |
| 170 #endif // BLIMP_NET_HELIUM_SYNCABLE_H_ | |
| OLD | NEW |