Chromium Code Reviews| Index: blimp/net/helium/syncable.h |
| diff --git a/blimp/net/helium/syncable.h b/blimp/net/helium/syncable.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..458513f7ee7fb7ae3ce65995efa4b7fe989dda59 |
| --- /dev/null |
| +++ b/blimp/net/helium/syncable.h |
| @@ -0,0 +1,137 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#ifndef BLIMP_NET_HELIUM_SYNCABLE_H_ |
| +#define BLIMP_NET_HELIUM_SYNCABLE_H_ |
| + |
| +#include <stdint.h> |
| +#include <memory> |
| + |
| +#include "base/macros.h" |
| +#include "blimp/net/helium/vector_clock.h" |
| + |
| +namespace blimp { |
| + |
| +namespace proto { |
| +class ChangesetMessage; |
| +} |
| + |
| +// Syncable is a base class interface that is used for both SyncableObject and |
| +// SyncableMember classes. |
| +// |
| +// Syncable is something that supports creating and restoring Changesets. |
| +// Changesets is a state that is propagated between client and server to |
|
Kevin M
2016/10/04 17:28:12
Suggestion: Objects exchange Changesets between th
scf
2016/10/04 21:27:46
Done.
|
| +// keep corresponding objects eventually synchronized. |
| +// |
| +// 1. Mapping: There is a one-to-one relationship between instances on the |
| +// client and instances on the engine. |
| +// 2. Consistency: The values stored in client-engine pairs should eventually be |
| +// equal. |
| +// |
| +// The main difference is that SyncableObject owns its lifetime, whereas |
| +// SyncableMember depends on its SyncableObject parent. |
| +// |
| +// An example for GeoLocation would be: |
| +// GeoLocation : SyncableObject { |
| +// * Frequency : SyncableMember |
| +// * Position : SyncableMember |
| +// } |
| +// |
| +// VectorClocks from a SyncableMember can be compared with the VectorClock from |
| +// the SyncableObject. This reduces the amount of state that needs to be kept. |
| + |
| +template <class ChangesetType> |
| +class Syncable { |
| + public: |
| + virtual ~Syncable() {} |
| + |
| + // Constructs a changeset between the |from| revision and its current state. |
| + // The Sync layer will encapsulate the changeset with details since |from|, |
| + // but the Object is responsible for including any revision information |
| + // additional to that expressed by the VectorClocks, that is necessary to |
| + // detect and resolve conflicts. |
| + // The computed changeset is returned asynchronously as a return parameter. |
| + virtual std::unique_ptr<ChangesetType> CreateChangesetToCurrent( |
| + const VectorClock& from) = 0; |
| + |
| + // Applies a |changeset| given as parameter to the contents of the |
| + // Syncable. |
| + // The VectorClocks |from| and |to| can be used to detect and resolve |
| + // concurrent change conflicts. |
| + virtual void ApplyChangeset(const VectorClock& from, |
| + const VectorClock& to, |
| + std::unique_ptr<ChangesetType> changeset) = 0; |
|
Kevin M
2016/10/04 17:28:11
This one's going to have to be async. We need to g
scf
2016/10/04 21:27:46
After discussing offline with @kevin and @wez we d
|
| + |
| + // Gives a chance for the Syncable to delete any old data previous to the |
| + // |checkpoint|. This is a pretty important method that will remove some |
| + // memory pressure for example from the UniqueSet CRDTs. They need to keep |
| + // a growing list of added/removed elements over time. With this checkpoint |
| + // info they can delete those elements prior to the vector clock specified in |
| + // |checkpoint|. |
| + virtual void ReleaseCheckpointsBefore(const VectorClock& checkpoint) = 0; |
| +}; |
| + |
| +class SyncableObject : public Syncable<proto::ChangesetMessage> { |
| + public: |
| + explicit SyncableObject(const VectorClock& clock); |
| + ~SyncableObject() override {} |
| + |
| + const VectorClock& clock() const { return clock_; } |
| + |
| + VectorClock* mutable_clock() { return &clock_; } |
| + |
| + protected: |
| + // The clock is needed in order for the |SyncableMember| objects whenever |
| + // they modify their state they update their |last_modified_| value. |
| + // The rationale here is use a "global" per SyncableObject clock which makes |
| + // state management a lot simpler. |
| + VectorClock clock_; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(SyncableObject); |
| +}; |
| + |
| +template <class ChangesetType> |
| +class SyncableMember : public Syncable<ChangesetType> { |
| + public: |
| + explicit SyncableMember(SyncableObject* parent); |
| + ~SyncableMember() override {} |
| + |
| + // Returns true if the object have been modified since |from|. |
| + virtual bool ModifiedSince(const VectorClock& from) = 0; |
| + |
| + protected: |
| + // Increments the parent clock and returns the new value. Should be used |
| + // whenever a SyncableMember updates its state. |
| + VectorClock IncrementParentClock(); |
| + |
| + // Returns the current value of the vector clock of the parent object (aka |
| + // SyncableObject). |
| + const VectorClock& parent_clock() const; |
| + |
| + private: |
| + SyncableObject* parent_; |
| + DISALLOW_COPY_AND_ASSIGN(SyncableMember); |
| +}; |
| + |
| +SyncableObject::SyncableObject(const VectorClock& clock) : clock_(clock) {} |
| + |
| +template <class ChangesetType> |
| +SyncableMember<ChangesetType>::SyncableMember(SyncableObject* parent) |
| + : parent_(parent) {} |
| + |
| +template <class ChangesetType> |
| +VectorClock SyncableMember<ChangesetType>::IncrementParentClock() { |
| + parent_->mutable_clock()->IncrementLocal(); |
| + return parent_->clock(); |
| +} |
| + |
| +template <class ChangesetType> |
| +const VectorClock& SyncableMember<ChangesetType>::parent_clock() const { |
| + return parent_->clock(); |
| +} |
| + |
| +} // namespace blimp |
| + |
| +#endif // BLIMP_NET_HELIUM_SYNCABLE_H_ |