You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2014/02/27 02:44:35 UTC
git commit: Modified the Registrar to notify callers only _after_ the
storage operation completes.
Repository: mesos
Updated Branches:
refs/heads/master e2e844d3f -> a22fd3516
Modified the Registrar to notify callers only _after_ the storage operation completes.
Review: https://reviews.apache.org/r/18341
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/a22fd351
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/a22fd351
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/a22fd351
Branch: refs/heads/master
Commit: a22fd35160f96fcd2b2c73f40111314d00f285e2
Parents: e2e844d
Author: Benjamin Mahler <bm...@twitter.com>
Authored: Thu Feb 20 18:19:28 2014 -0800
Committer: Benjamin Mahler <bm...@twitter.com>
Committed: Wed Feb 26 17:44:21 2014 -0800
----------------------------------------------------------------------
src/master/registrar.cpp | 163 ++++++++++++++++++++++++------------------
1 file changed, 92 insertions(+), 71 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/a22fd351/src/master/registrar.cpp
----------------------------------------------------------------------
diff --git a/src/master/registrar.cpp b/src/master/registrar.cpp
index ee16121..37337c0 100644
--- a/src/master/registrar.cpp
+++ b/src/master/registrar.cpp
@@ -72,26 +72,47 @@ public:
private:
template <typename T>
- struct Mutation : process::Promise<bool>
+ struct Operation : process::Promise<bool>
{
- virtual Try<T> apply(T t) = 0;
+ Operation() : success(false) {}
+
+ // Attempts to invoke the operation on 't'.
+ // Returns Some if the operation mutates 't'.
+ // Returns None if the operation does not mutate 't'.
+ // Returns Error if the operation cannot be performed on 't'.
+ Result<T> operator () (T t)
+ {
+ const Result<T>& result = perform(t);
+
+ success = !result.isError();
+
+ return result;
+ }
+
+ // Sets the promise based on whether the operation was successful.
+ bool set() { return Promise<bool>::set(success); }
+
+ protected:
+ virtual Result<T> perform(T t) = 0;
+
+ private:
+ bool success;
};
- struct Admit : Mutation<Registry>
+ struct Admit : Operation<Registry>
{
Admit(const SlaveInfo& _info) : info(_info) {}
- virtual Try<Registry> apply(Registry registry)
+ protected:
+ virtual Result<Registry> perform(Registry registry)
{
// Check and see if this slave already exists.
foreach (const Registry::Slave& slave, registry.slaves().slaves()) {
if (slave.info().id() == info.id()) {
- set(false);
- return registry; // No mutation.
+ return Error("Slave already admitted");
}
}
- // Okay, add the slave!
Registry::Slave* slave = registry.mutable_slaves()->add_slaves();
slave->mutable_info()->CopyFrom(info);
return registry;
@@ -100,33 +121,31 @@ private:
const SlaveInfo info;
};
- // NOTE: Even though re-admission does not mutate the state, we
- // model it as a mutation so that it is performed in sequence with
- // other mutations.
- struct Readmit : Mutation<Registry>
+ struct Readmit : Operation<Registry>
{
Readmit(const SlaveInfo& _info) : info(_info) {}
- virtual Try<Registry> apply(Registry registry)
+ protected:
+ virtual Result<Registry> perform(Registry registry)
{
foreach (const Registry::Slave& slave, registry.slaves().slaves()) {
if (slave.info().id() == info.id()) {
- set(true);
- return registry;
+ return None();
}
}
- set(false);
- return registry;
+
+ return Error("Slave not yet admitted");
}
const SlaveInfo info;
};
- struct Remove : Mutation<Registry>
+ struct Remove : Operation<Registry>
{
Remove(const SlaveInfo& _info) : info(_info) {}
- virtual Try<Registry> apply(Registry registry)
+ protected:
+ virtual Result<Registry> perform(Registry registry)
{
for (int i = 0; i < registry.slaves().slaves().size(); i++) {
const Registry::Slave& slave = registry.slaves().slaves(i);
@@ -139,15 +158,14 @@ private:
}
}
- set(false);
- return registry;
+ return Error("Slave not yet admitted");
}
const SlaveInfo info;
};
Option<Variable<Registry> > variable;
- deque<Mutation<Registry>*> mutations;
+ deque<Operation<Registry>*> operations;
bool updating; // Used to signify fetching (recovering) or storing.
// Continuations.
@@ -161,8 +179,9 @@ private:
// Helper for updating state (performing store).
void update();
- Future<bool> _update(const Option<Variable<Registry> >& variable);
- void __update(const string& message);
+ void _update(
+ const Future<Option<Variable<Registry> > >& store,
+ deque<Operation<Registry>*> operations);
State* state;
@@ -223,9 +242,9 @@ Future<bool> RegistrarProcess::admit(const SlaveInfo& info)
Future<bool> RegistrarProcess::_admit(const SlaveInfo& info)
{
CHECK_SOME(variable);
- Mutation<Registry>* mutation = new Admit(info);
- mutations.push_back(mutation);
- Future<bool> future = mutation->future();
+ Operation<Registry>* operation = new Admit(info);
+ operations.push_back(operation);
+ Future<bool> future = operation->future();
if (!updating) {
update();
}
@@ -253,9 +272,9 @@ Future<bool> RegistrarProcess::_readmit(
return Failure("Expecting SlaveInfo to have a SlaveID");
}
- Mutation<Registry>* mutation = new Readmit(info);
- mutations.push_back(mutation);
- Future<bool> future = mutation->future();
+ Operation<Registry>* operation = new Readmit(info);
+ operations.push_back(operation);
+ Future<bool> future = operation->future();
if (!updating) {
update();
}
@@ -283,9 +302,9 @@ Future<bool> RegistrarProcess::_remove(
return Failure("Expecting SlaveInfo to have a SlaveID");
}
- Mutation<Registry>* mutation = new Remove(info);
- mutations.push_back(mutation);
- Future<bool> future = mutation->future();
+ Operation<Registry>* operation = new Remove(info);
+ operations.push_back(operation);
+ Future<bool> future = operation->future();
if (!updating) {
update();
}
@@ -295,7 +314,7 @@ Future<bool> RegistrarProcess::_remove(
void RegistrarProcess::update()
{
- if (mutations.empty()) {
+ if (operations.empty()) {
return; // No-op.
}
@@ -303,69 +322,71 @@ void RegistrarProcess::update()
updating = true;
- LOG(INFO) << "Attempting to update 'registry'";
+ LOG(INFO) << "Attempting to update the 'registry'";
CHECK_SOME(variable);
Variable<Registry> variable_ = variable.get();
- foreach (Mutation<Registry>* mutation, mutations) {
- Try<Registry> registry = mutation->apply(variable_.get());
- if (registry.isError()) {
- mutation->fail("Failed to mutate 'registry': " + registry.error());
- } else {
+ foreach (Operation<Registry>* operation, operations) {
+ const Result<Registry>& registry = (*operation)(variable_.get());
+ if (registry.isSome()) {
variable_ = variable_.mutate(registry.get());
}
}
- // Perform the store! Save the future so we can associate it with
- // the mutations that are part of this update.
- Future<bool> future = state->store(variable_)
- .then(defer(self(), &Self::_update, lambda::_1));
-
// TODO(benh): Add a timeout so we don't wait forever.
- // Toggle 'updating' if the store fails or is discarded.
- future
- .onDiscarded(defer(self(), &Self::__update, "discarded"))
- .onFailed(defer(self(), &Self::__update, lambda::_1));
-
- // Now associate the store with all the mutations.
- while (!mutations.empty()) {
- Mutation<Registry>* mutation = mutations.front();
- mutations.pop_front();
- mutation->associate(future); // No-op if already failed above.
- delete mutation;
- }
+ // Perform the store!
+ state->store(variable_)
+ .onAny(defer(self(), &Self::_update, lambda::_1, operations));
+
+ // Clear the operations, _update will transition the Promises!
+ operations.clear();
}
-Future<bool> RegistrarProcess::_update(
- const Option<Variable<Registry> >& variable_)
+void RegistrarProcess::_update(
+ const Future<Option<Variable<Registry> > >& store,
+ deque<Operation<Registry>*> operations)
{
updating = false;
- if (variable_.isNone()) {
+ // Set the variable if the storage operation succeeded.
+ if (!store.isReady()) {
+ LOG(ERROR) << "Failed to update 'registry': "
+ << (store.isFailed() ? store.failure() : "discarded");
+ } else if (store.get().isNone()) {
LOG(WARNING) << "Failed to update 'registry': version mismatch";
- return Failure("Failed to update 'registry': version mismatch");
+ } else {
+ LOG(INFO) << "Successfully updated 'registry'";
+ variable = store.get().get();
}
- LOG(INFO) << "Successfully updated 'registry'";
+ // Remove the operations.
+ while (!operations.empty()) {
+ Operation<Registry>* operation = operations.front();
+ operations.pop_front();
- variable = variable_.get();
+ if (!store.isReady()) {
+ operation->fail("Failed to update 'registry': " +
+ (store.isFailed() ? store.failure() : "discarded"));
+ } else {
+ if (store.get().isNone()) {
+ operation->fail("Failed to update 'registry': version mismatch");
+ } else {
+ operation->set();
+ }
+ }
- if (!mutations.empty()) {
- update();
+ delete operation;
}
- return true;
-}
-
+ operations.clear();
-void RegistrarProcess::__update(const string& message)
-{
- LOG(WARNING) << "Failed to update 'registry': " << message;
- updating = false;
+ if (!this->operations.empty()) {
+ update();
+ }
}