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..5ddb5c0d8a39a0237146d6bf14ef0efb3c5d4c3a |
| --- /dev/null |
| +++ b/blimp/net/helium/syncable.h |
| @@ -0,0 +1,126 @@ |
| +// 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/common/proto/helium.pb.h" |
| +#include "blimp/net/helium/vector_clock.h" |
| + |
| +namespace blimp { |
| + |
| +// SyncableObject and SyncableMember are conceptually very similar. |
|
Kevin M
2016/10/03 21:44:26
Include a description about what a Syncable<> is h
scf
2016/10/03 22:20:17
Done.
|
| +// Both are objects that will be synchronized between client and engine. |
|
Kevin M
2016/10/03 21:44:26
This seems to pigeonhole in the differences and si
scf
2016/10/03 22:20:17
Done.
|
| +// |
| +// 1. There is a one-to-one relationship between instances on the client and |
| +// instances on the engine. |
| +// 2. 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; |
| + |
| + // 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<helium::ChangesetMessage> { |
| + public: |
| + SyncableObject(); |
|
Kevin M
2016/10/03 21:44:26
What will this be used for?
scf
2016/10/03 22:20:17
Done.
|
| + explicit SyncableObject(const VectorClock& clock); |
| + ~SyncableObject() override {} |
| + |
| + const VectorClock& clock() { return clock_; } |
|
Kevin M
2016/10/03 21:44:26
Method should be const.
scf
2016/10/03 22:20:17
Done.
|
| + |
| + VectorClock* mutable_clock() { return &clock_; } |
|
Kevin M
2016/10/03 21:44:26
Method should be const.
scf
2016/10/03 22:20:18
cannot return pointer of member in a const method
|
| + |
| + 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_; |
|
Kevin M
2016/10/03 21:44:26
If we are using a global clock, then we should tak
scf
2016/10/03 22:20:17
yes it will be done in a separate cl as discussed
|
| + |
| + 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| |
|
Kevin M
2016/10/03 21:44:26
trailing period.
scf
2016/10/03 22:20:17
Done.
|
| + 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(); |
|
Kevin M
2016/10/03 21:44:26
Should we also have a method for getting the paren
scf
2016/10/03 22:20:18
Done.
|
| + |
| + SyncableObject* parent_; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(SyncableMember); |
| +}; |
| + |
| +// Actual implementations are inline because of template instantiation |
| + |
| +SyncableObject::SyncableObject() : clock_() {} |
| + |
| +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(); |
| +} |
| + |
| +} // namespace blimp |
| + |
| +#endif // BLIMP_NET_HELIUM_SYNCABLE_H_ |