TEST(Statistics, truncate) { Clock::pause(); Statistics statistics(seconds(60*60*24)); statistics.set("statistic", 3.14); Future<map<seconds, double> > values = statistics.get("statistic"); values.await(); ASSERT_TRUE(values.isReady()); EXPECT_EQ(1, values.get().size()); EXPECT_GE(Clock::now(), values.get().begin()->first.value); EXPECT_DOUBLE_EQ(3.14, values.get().begin()->second); Clock::advance((60*60*24) + 1); statistics.increment("statistic"); values = statistics.get("statistic"); values.await(); ASSERT_TRUE(values.isReady()); EXPECT_EQ(1, values.get().size()); EXPECT_GE(Clock::now(), values.get().begin()->first.value); EXPECT_DOUBLE_EQ(4.14, values.get().begin()->second); Clock::resume(); }
TEST(Statistics, truncate) { Clock::pause(); Statistics statistics(Days(1)); statistics.set("test", "statistic", 3.0); Future<map<Seconds, double> > values = statistics.timeseries("test", "statistic"); values.await(); ASSERT_TRUE(values.isReady()); EXPECT_EQ(1, values.get().size()); EXPECT_GE(Clock::now(), values.get().begin()->first.secs()); EXPECT_DOUBLE_EQ(3.0, values.get().begin()->second); Clock::advance((60*60*24) + 1); statistics.increment("test", "statistic"); values = statistics.timeseries("test", "statistic"); values.await(); ASSERT_TRUE(values.isReady()); EXPECT_EQ(1, values.get().size()); EXPECT_GE(Clock::now(), values.get().begin()->first.secs()); EXPECT_DOUBLE_EQ(4.0, values.get().begin()->second); Clock::resume(); }
TEST(ProcessTest, Defer2) { ASSERT_TRUE(GTEST_IS_THREADSAFE); DeferProcess process; PID<DeferProcess> pid = spawn(process); Future<string> f = dispatch(pid, &DeferProcess::func1, 41); f.await(); ASSERT_TRUE(f.isReady()); EXPECT_EQ("41", f.get()); f = dispatch(pid, &DeferProcess::func2, 41); f.await(); ASSERT_TRUE(f.isReady()); EXPECT_EQ("42", f.get()); terminate(pid); wait(pid); }
Future<Nothing> HealthCheckerProcess::__tcpHealthCheck( const tuple< Future<Option<int>>, Future<string>, Future<string>>& t) { Future<Option<int>> status = std::get<0>(t); if (!status.isReady()) { return Failure( "Failed to get the exit status of the " + string(TCP_CHECK_COMMAND) + " process: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure( "Failed to reap the " + string(TCP_CHECK_COMMAND) + " process"); } int statusCode = status->get(); if (statusCode != 0) { Future<string> error = std::get<2>(t); if (!error.isReady()) { return Failure( string(TCP_CHECK_COMMAND) + " returned " + WSTRINGIFY(statusCode) + "; reading stderr failed: " + (error.isFailed() ? error.failure() : "discarded")); } return Failure( string(TCP_CHECK_COMMAND) + " returned " + WSTRINGIFY(statusCode) + ": " + error.get()); } return Nothing(); }
TEST(IO, Read) { ASSERT_TRUE(GTEST_IS_THREADSAFE); int pipes[2]; char data[3]; // Create a blocking pipe. ASSERT_NE(-1, ::pipe(pipes)); // Test on a blocking file descriptor. AWAIT_EXPECT_FAILED(io::read(pipes[0], data, 3)); close(pipes[0]); close(pipes[1]); // Test on a closed file descriptor. AWAIT_EXPECT_FAILED(io::read(pipes[0], data, 3)); // Create a nonblocking pipe. ASSERT_NE(-1, ::pipe(pipes)); ASSERT_SOME(os::nonblock(pipes[0])); ASSERT_SOME(os::nonblock(pipes[1])); // Test reading nothing. AWAIT_EXPECT_FAILED(io::read(pipes[0], data, 0)); // Test successful read. Future<size_t> future = io::read(pipes[0], data, 3); ASSERT_FALSE(future.isReady()); ASSERT_EQ(2, write(pipes[1], "hi", 2)); AWAIT_ASSERT_EQ(2u, future); EXPECT_EQ('h', data[0]); EXPECT_EQ('i', data[1]); // Test cancellation. future = io::read(pipes[0], data, 1); ASSERT_FALSE(future.isReady()); future.discard(); ASSERT_EQ(3, write(pipes[1], "omg", 3)); AWAIT_ASSERT_EQ(3u, io::read(pipes[0], data, 3)); EXPECT_EQ('o', data[0]); EXPECT_EQ('m', data[1]); EXPECT_EQ('g', data[2]); // Test read EOF. future = io::read(pipes[0], data, 3); ASSERT_FALSE(future.isReady()); close(pipes[1]); AWAIT_ASSERT_EQ(0u, future); close(pipes[0]); }
TEST(Future, toUnitWhileInProgress) { Promise<int> p; Future<Unit> fu = p.getFuture().unit(); EXPECT_FALSE(fu.isReady()); p.setValue(42); EXPECT_TRUE(fu.isReady()); }
TEST(Future, unwrap) { Promise<int> a; Promise<int> b; auto fa = a.getFuture(); auto fb = b.getFuture(); bool flag1 = false; bool flag2 = false; // do a, then do b, and get the result of a + b. Future<int> f = fa.then([&](Try<int>&& ta) { auto va = ta.value(); flag1 = true; return fb.then([va, &flag2](Try<int>&& tb) { flag2 = true; return va + tb.value(); }); }); EXPECT_FALSE(flag1); EXPECT_FALSE(flag2); EXPECT_FALSE(f.isReady()); a.setValue(3); EXPECT_TRUE(flag1); EXPECT_FALSE(flag2); EXPECT_FALSE(f.isReady()); b.setValue(4); EXPECT_TRUE(flag1); EXPECT_TRUE(flag2); EXPECT_EQ(7, f.value()); }
Future<Nothing> HealthCheckerProcess::__httpHealthCheck( const tuple< Future<Option<int>>, Future<string>, Future<string>>& t) { Future<Option<int>> status = std::get<0>(t); if (!status.isReady()) { return Failure( "Failed to get the exit status of the " + string(HTTP_CHECK_COMMAND) + " process: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure( "Failed to reap the " + string(HTTP_CHECK_COMMAND) + " process"); } int statusCode = status->get(); if (statusCode != 0) { Future<string> error = std::get<2>(t); if (!error.isReady()) { return Failure( string(HTTP_CHECK_COMMAND) + " returned " + WSTRINGIFY(statusCode) + "; reading stderr failed: " + (error.isFailed() ? error.failure() : "discarded")); } return Failure( string(HTTP_CHECK_COMMAND) + " returned " + WSTRINGIFY(statusCode) + ": " + error.get()); } Future<string> output = std::get<1>(t); if (!output.isReady()) { return Failure( "Failed to read stdout from " + string(HTTP_CHECK_COMMAND) + ": " + (output.isFailed() ? output.failure() : "discarded")); } // Parse the output and get the HTTP response code. Try<int> code = numify<int>(output.get()); if (code.isError()) { return Failure( "Unexpected output from " + string(HTTP_CHECK_COMMAND) + ": " + output.get()); } if (code.get() < process::http::Status::OK || code.get() >= process::http::Status::BAD_REQUEST) { return Failure( "Unexpected HTTP response code: " + process::http::Status::string(code.get())); } return Nothing(); }
Future<Nothing> untar(const string& file, const string& directory) { const vector<string> argv = { "tar", "-C", directory, "-x", "-f", file }; Try<Subprocess> s = subprocess( "tar", argv, Subprocess::PATH("/dev/null"), Subprocess::PATH("/dev/null"), Subprocess::PIPE()); if (s.isError()) { return Failure("Failed to execute the subprocess: " + s.error()); } return await( s.get().status(), process::io::read(s.get().err().get())) .then([](const tuple< Future<Option<int>>, Future<string>>& t) -> Future<Nothing> { Future<Option<int>> status = std::get<0>(t); if (!status.isReady()) { return Failure( "Failed to get the exit status of the subprocess: " + (status.isFailed() ? status.failure() : "discarded")); } Future<string> error = std::get<1>(t); if (!error.isReady()) { return Failure( "Failed to read stderr from the subprocess: " + (error.isFailed() ? error.failure() : "discarded")); } if (status->isNone()) { return Failure("Failed to reap the subprocess"); } if (status->get() != 0) { return Failure( "Unexpected result from the subprocess: " + WSTRINGIFY(status->get()) + ", stderr='" + error.get() + "'"); } return Nothing(); }); }
TEST(ReplicaTest, Promise) { const std::string path = utils::os::getcwd() + "/.log"; utils::os::rmdir(path); Replica replica(path); PromiseRequest request; PromiseResponse response; Future<PromiseResponse> future; request.set_id(2); future = protocol::promise(replica.pid(), request); future.await(2.0); ASSERT_TRUE(future.isReady()); response = future.get(); EXPECT_TRUE(response.okay()); EXPECT_EQ(2, response.id()); EXPECT_TRUE(response.has_position()); EXPECT_EQ(0, response.position()); EXPECT_FALSE(response.has_action()); request.set_id(1); future = protocol::promise(replica.pid(), request); future.await(2.0); ASSERT_TRUE(future.isReady()); response = future.get(); EXPECT_FALSE(response.okay()); EXPECT_EQ(1, response.id()); EXPECT_FALSE(response.has_position()); EXPECT_FALSE(response.has_action()); request.set_id(3); future = protocol::promise(replica.pid(), request); future.await(2.0); ASSERT_TRUE(future.isReady()); response = future.get(); EXPECT_TRUE(response.okay()); EXPECT_EQ(3, response.id()); EXPECT_TRUE(response.has_position()); EXPECT_EQ(0, response.position()); EXPECT_FALSE(response.has_action()); utils::os::rmdir(path); }
// Makes sure that the unwrap call also works when the promise was not yet // fulfilled, and that the returned Future<T> becomes ready once the promise // is fulfilled. TEST(Unwrap, futureNotReady) { Promise<Future<int>> p; Future<Future<int>> future = p.getFuture(); Future<int> unwrapped = future.unwrap(); // Sanity - should not be ready before the promise is fulfilled. ASSERT_FALSE(unwrapped.isReady()); // Fulfill the promise and make sure the unwrapped future is now ready. p.setValue(makeFuture(5484)); ASSERT_TRUE(unwrapped.isReady()); EXPECT_EQ(5484, unwrapped.value()); }
Future<Nothing> NetworkCniIsolatorProcess::_detach( const ContainerID& containerId, const std::string& networkName, const string& plugin, const tuple<Future<Option<int>>, Future<string>>& t) { CHECK(infos.contains(containerId)); CHECK(infos[containerId]->containerNetworks.contains(networkName)); Future<Option<int>> status = std::get<0>(t); if (!status.isReady()) { return Failure( "Failed to get the exit status of the CNI plugin '" + plugin + "' subprocess: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure( "Failed to reap the CNI plugin '" + plugin + "' subprocess"); } if (status.get() == 0) { const string ifDir = paths::getInterfaceDir( rootDir.get(), containerId.value(), networkName, infos[containerId]->containerNetworks[networkName].ifName); Try<Nothing> rmdir = os::rmdir(ifDir); if (rmdir.isError()) { return Failure( "Failed to remove interface directory '" + ifDir + "': " + rmdir.error()); } return Nothing(); } // CNI plugin will print result (in case of success) or error (in // case of failure) to stdout. Future<string> output = std::get<1>(t); if (!output.isReady()) { return Failure( "Failed to read stdout from the CNI plugin '" + plugin + "' subprocess: " + (output.isFailed() ? output.failure() : "discarded")); } return Failure( "The CNI plugin '" + plugin + "' failed to detach container " "from network '" + networkName + "': " + output.get()); }
static Future<Nothing> _fetch(const Future<std::tuple< Future<Option<int>>, Future<string>, Future<string>>>& future) { CHECK_READY(future); Future<Option<int>> status = std::get<0>(future.get()); if (!status.isReady()) { return Failure( "Failed to get the exit status of the curl subprocess: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure("Failed to reap the curl subprocess"); } if (status->get() != 0) { Future<string> error = std::get<2>(future.get()); if (!error.isReady()) { return Failure( "Failed to perform 'curl'. Reading stderr failed: " + (error.isFailed() ? error.failure() : "discarded")); } return Failure("Failed to perform 'curl': " + error.get()); } Future<string> output = std::get<1>(future.get()); if (!output.isReady()) { return Failure( "Failed to read stdout from 'curl': " + (output.isFailed() ? output.failure() : "discarded")); } // Parse the output and get the HTTP response code. Try<int> code = numify<int>(output.get()); if (code.isError()) { return Failure("Unexpected output from 'curl': " + output.get()); } if (code.get() != http::Status::OK) { return Failure( "Unexpected HTTP response code: " + http::Status::string(code.get())); } return Nothing(); }
TEST(DecoderTest, StreamingResponse) { StreamingResponseDecoder decoder; const string headers = "HTTP/1.1 200 OK\r\n" "Date: Fri, 31 Dec 1999 23:59:59 GMT\r\n" "Content-Type: text/plain\r\n" "Content-Length: 2\r\n" "\r\n"; const string body = "hi"; deque<http::Response*> responses = decoder.decode(headers.data(), headers.length()); EXPECT_FALSE(decoder.failed()); EXPECT_TRUE(decoder.writingBody()); ASSERT_EQ(1, responses.size()); Owned<http::Response> response(responses[0]); EXPECT_EQ("200 OK", response->status); EXPECT_EQ(3, response->headers.size()); ASSERT_EQ(http::Response::PIPE, response->type); ASSERT_SOME(response->reader); http::Pipe::Reader reader = response->reader.get(); Future<string> read = reader.read(); EXPECT_TRUE(read.isPending()); decoder.decode(body.data(), body.length()); EXPECT_FALSE(decoder.failed()); EXPECT_FALSE(decoder.writingBody()); // Feeding EOF to the decoder should be ok. decoder.decode("", 0); EXPECT_FALSE(decoder.failed()); EXPECT_FALSE(decoder.writingBody()); EXPECT_TRUE(read.isReady()); EXPECT_EQ("hi", read.get()); // Response should be complete. read = reader.read(); EXPECT_TRUE(read.isReady()); EXPECT_EQ("", read.get()); }
TEST(HTTPTest, PipeEOF) { http::Pipe pipe; http::Pipe::Reader reader = pipe.reader(); http::Pipe::Writer writer = pipe.writer(); // A 'read' on an empty pipe should block. Future<string> read = reader.read(); EXPECT_TRUE(read.isPending()); // Writing an empty string should have no effect. EXPECT_TRUE(writer.write("")); EXPECT_TRUE(read.isPending()); // After a 'write' the pending 'read' should complete. EXPECT_TRUE(writer.write("hello")); ASSERT_TRUE(read.isReady()); EXPECT_EQ("hello", read.get()); // After a 'write' a call to 'read' should be completed immediately. ASSERT_TRUE(writer.write("world")); read = reader.read(); ASSERT_TRUE(read.isReady()); EXPECT_EQ("world", read.get()); // Close the write end of the pipe and ensure the remaining // data can be read. EXPECT_TRUE(writer.write("!")); EXPECT_TRUE(writer.close()); AWAIT_EQ("!", reader.read()); // End of file should be reached. AWAIT_EQ("", reader.read()); AWAIT_EQ("", reader.read()); // Writes to a pipe with the write end closed are ignored. EXPECT_FALSE(writer.write("!")); AWAIT_EQ("", reader.read()); // The write end cannot be closed twice. EXPECT_FALSE(writer.close()); // Close the read end, this should not notify the writer // since the write end was already closed. EXPECT_TRUE(reader.close()); EXPECT_TRUE(writer.readerClosed().isPending()); }
Future<bool> LeaderContenderProcess::withdraw() { if (contending.isNone()) { // Nothing to withdraw because the contender has not contended. return false; } if (withdrawing.isSome()) { // Repeated calls to withdraw get the same result. return withdrawing.get(); } withdrawing = new Promise<bool>(); CHECK(!candidacy.isDiscarded()); if (candidacy.isPending()) { // If we have not obtained the candidacy yet, we withdraw after // it is obtained. LOG(INFO) << "Withdraw requested before the candidacy is obtained; will " << "withdraw after it happens"; candidacy.onAny(defer(self(), &Self::cancel)); } else if (candidacy.isReady()) { cancel(); } else { // We have failed to obtain the candidacy so we do not need to // cancel it. return false; } return withdrawing.get()->future(); }
TEST(Process, collect) { ASSERT_TRUE(GTEST_IS_THREADSAFE); Promise<int> promise1; Promise<int> promise2; Promise<int> promise3; Promise<int> promise4; std::list<Future<int> > futures; futures.push_back(promise1.future()); futures.push_back(promise2.future()); futures.push_back(promise3.future()); futures.push_back(promise4.future()); promise1.set(1); promise2.set(2); promise3.set(3); promise4.set(4); Future<std::list<int> > future = collect(futures); EXPECT_TRUE(future.await()); EXPECT_TRUE(future.isReady()); std::list<int> values; values.push_back(1); values.push_back(2); values.push_back(3); values.push_back(4); EXPECT_EQ(values, future.get()); }
void LeaderContenderProcess::cancelled(const Future<bool>& result) { CHECK(candidacy.isReady()); LOG(INFO) << "Membership cancelled: " << candidacy.get().id(); // Can be called as a result of either withdraw() or server side // expiration. CHECK(withdrawing.isSome() || watching.isSome()); CHECK(!result.isDiscarded()); if (result.isFailed()) { if (withdrawing.isSome()) { withdrawing.get()->fail(result.failure()); } if (watching.isSome()) { watching.get()->fail(result.failure()); } } else { if (withdrawing.isSome()) { withdrawing.get()->set(result); } if (watching.isSome()) { watching.get()->set(Nothing()); } } }
// Master contention and detection fail when the network is down, it // recovers when the network is back up. TEST_F(ZooKeeperMasterContenderDetectorTest, ContenderDetectorShutdownNetwork) { Clock::pause(); Try<zookeeper::URL> url = zookeeper::URL::parse( "zk://" + server->connectString() + "/mesos"); ASSERT_SOME(url); ZooKeeperMasterContender contender(url.get()); PID<Master> master; master.ip = 10000000; master.port = 10000; contender.initialize(master); Future<Future<Nothing> > contended = contender.contend(); AWAIT_READY(contended); Future<Nothing> lostCandidacy = contended.get(); ZooKeeperMasterDetector detector(url.get()); Future<Option<UPID> > leader = detector.detect(); AWAIT_READY(leader); EXPECT_SOME_EQ(master, leader.get()); leader = detector.detect(leader.get()); // Shut down ZooKeeper and expect things to fail after the timeout. server->shutdownNetwork(); // We may need to advance multiple times because we could have // advanced the clock before the timer in Group starts. while (lostCandidacy.isPending()) { Clock::advance(MASTER_CONTENDER_ZK_SESSION_TIMEOUT); Clock::settle(); } // Local timeout does not fail the future but rather deems the // session has timed out and the candidacy is lost. EXPECT_TRUE(lostCandidacy.isReady()); // Re-contend (and continue detecting). contended = contender.contend(); // Things will not change until the server restarts. Clock::advance(Minutes(1)); Clock::settle(); EXPECT_TRUE(contended.isPending()); EXPECT_TRUE(leader.isPending()); server->startNetwork(); // Operations will eventually succeed after ZK is restored. AWAIT_READY(contended); AWAIT_READY(leader); Clock::resume(); }
bool SlavesManager::deactivate(const string& hostname, uint16_t port) { // Make sure the slave is currently activated. if (active.contains(hostname, port)) { // Get the storage system to persist the deactivation. Future<bool> deactivated = process::dispatch(storage->self(), &SlavesManagerStorage::deactivate, hostname, port); deactivated.await(); if (deactivated.isReady() && deactivated.get()) { active.remove(hostname, port); inactive.put(hostname, port); // Tell the master that this slave is now deactivated. process::dispatch(master, &Master::deactivatedSlaveHostnamePort, hostname, port); return true; } } return false; }
bool SlavesManager::remove(const string& hostname, uint16_t port) { // Make sure the slave is currently activated or deactivated. if (!active.contains(hostname, port) && !inactive.contains(hostname, port)) { LOG(WARNING) << "Attempted to remove unknown slave!"; return false; } // Get the storage system to persist the removal. Future<bool> removed = process::dispatch(storage->self(), &SlavesManagerStorage::remove, hostname, port); removed.await(); if (removed.isReady() && removed.get()) { active.remove(hostname, port); inactive.remove(hostname, port); // Tell the master that this slave is now deactivated. process::dispatch(master, &Master::deactivatedSlaveHostnamePort, hostname, port); return true; } return false; }
TEST(Statistics, set) { Statistics statistics(Days(1)); // Set one using Clock::now() implicitly. statistics.set("test", "statistic", 3.0); // Set one using Clock::now() explicitly. Seconds now(Clock::now()); statistics.set("test", "statistic", 4.0, now); Future<map<Seconds, double> > values = statistics.timeseries("test", "statistic"); values.await(); ASSERT_TRUE(values.isReady()); EXPECT_EQ(2, values.get().size()); EXPECT_GE(Clock::now(), values.get().begin()->first.secs()); EXPECT_DOUBLE_EQ(3.0, values.get().begin()->second); EXPECT_EQ(1, values.get().count(now)); EXPECT_DOUBLE_EQ(4.0, values.get()[now]); }
/* * Class: org_apache_mesos_state_ZooKeeperState * Method: __expunge_get * Signature: (J)Ljava/lang/Boolean; */ JNIEXPORT jobject JNICALL Java_org_apache_mesos_state_ZooKeeperState__1_1expunge_1get (JNIEnv* env, jobject thiz, jlong jfuture) { Future<bool>* future = (Future<bool>*) jfuture; future->await(); if (future->isFailed()) { jclass clazz = env->FindClass("java/util/concurrent/ExecutionException"); env->ThrowNew(clazz, future->failure().c_str()); return NULL; } else if (future->isDiscarded()) { jclass clazz = env->FindClass("java/util/concurrent/CancellationException"); env->ThrowNew(clazz, "Future was discarded"); return NULL; } CHECK(future->isReady()); if (future->get()) { jclass clazz = env->FindClass("java/lang/Boolean"); return env->GetStaticObjectField( clazz, env->GetStaticFieldID(clazz, "TRUE", "Ljava/lang/Boolean;")); } jclass clazz = env->FindClass("java/lang/Boolean"); return env->GetStaticObjectField( clazz, env->GetStaticFieldID(clazz, "FALSE", "Ljava/lang/Boolean;")); }
TEST(FutureTest, Chain) { Future<string> s = readyFuture() .then(lambda::bind(&second, lambda::_1)) .then(lambda::bind(&third, lambda::_1)); s.await(); ASSERT_TRUE(s.isReady()); EXPECT_EQ("true", s.get()); s = failedFuture() .then(lambda::bind(&second, lambda::_1)) .then(lambda::bind(&third, lambda::_1)); s.await(); ASSERT_TRUE(s.isFailed()); Promise<bool> promise; s = pendingFuture(promise.future()) .then(lambda::bind(&second, lambda::_1)) .then(lambda::bind(&third, lambda::_1)); ASSERT_TRUE(s.isPending()); promise.discard(); AWAIT_DISCARDED(s); }
/* * Class: org_apache_mesos_state_ZooKeeperState * Method: __fetch_get * Signature: (J)Lorg/apache/mesos/state/Variable; */ JNIEXPORT jobject JNICALL Java_org_apache_mesos_state_ZooKeeperState__1_1fetch_1get (JNIEnv* env, jobject thiz, jlong jfuture) { Future<Variable>* future = (Future<Variable>*) jfuture; future->await(); if (future->isFailed()) { jclass clazz = env->FindClass("java/util/concurrent/ExecutionException"); env->ThrowNew(clazz, future->failure().c_str()); return NULL; } else if (future->isDiscarded()) { jclass clazz = env->FindClass("java/util/concurrent/CancellationException"); env->ThrowNew(clazz, "Future was discarded"); return NULL; } CHECK(future->isReady()); Variable* variable = new Variable(future->get()); // Variable variable = new Variable(); jclass clazz = env->FindClass("org/apache/mesos/state/Variable"); jmethodID _init_ = env->GetMethodID(clazz, "<init>", "()V"); jobject jvariable = env->NewObject(clazz, _init_); jfieldID __variable = env->GetFieldID(clazz, "__variable", "J"); env->SetLongField(jvariable, __variable, (jlong) variable); return jvariable; }
bool SlavesManager::add(const string& hostname, uint16_t port) { // Ignore request if slave is already active. if (active.contains(hostname, port)) { LOG(WARNING) << "Attempted to add an already added slave!"; return false; } // Make sure this slave is not currently deactivated. if (inactive.contains(hostname, port)) { LOG(WARNING) << "Attempted to add a deactivated slave, " << "try activating it instead!"; return false; } // Ask the storage system to persist the addition. Future<bool> added = process::dispatch(storage->self(), &SlavesManagerStorage::add, hostname, port); added.await(); if (added.isReady() && added.get()) { active.put(hostname, port); // Tell the master that this slave is now active. process::dispatch(master, &Master::activatedSlaveHostnamePort, hostname, port); return true; } return false; }
void RegistrarProcess::_recover( const MasterInfo& info, const Future<Variable<Registry> >& recovery) { updating = false; CHECK(!recovery.isPending()); if (!recovery.isReady()) { recovered.get()->fail("Failed to recover registrar: " + (recovery.isFailed() ? recovery.failure() : "discarded")); } else { Duration elapsed = metrics.state_fetch.stop(); LOG(INFO) << "Successfully fetched the registry" << " (" << Bytes(recovery.get().get().ByteSize()) << ")" << " in " << elapsed; // Save the registry. variable = recovery.get(); // Perform the Recover operation to add the new MasterInfo. Owned<Operation> operation(new Recover(info)); operations.push_back(operation); operation->future() .onAny(defer(self(), &Self::__recover, lambda::_1)); update(); } }
TEST(HTTPTest, PipeReaderCloses) { http::Pipe pipe; http::Pipe::Reader reader = pipe.reader(); http::Pipe::Writer writer = pipe.writer(); // If the read end of the pipe is closed, // it should discard any unread data. EXPECT_TRUE(writer.write("hello")); EXPECT_TRUE(writer.write("world")); // The writer should discover the closure. Future<Nothing> closed = writer.readerClosed(); EXPECT_TRUE(reader.close()); EXPECT_TRUE(closed.isReady()); // The read end is closed, subsequent reads will fail. AWAIT_FAILED(reader.read()); // The read end is closed, writes are ignored. EXPECT_FALSE(writer.write("!")); AWAIT_FAILED(reader.read()); // The read end cannot be closed twice. EXPECT_FALSE(reader.close()); // Close the write end. EXPECT_TRUE(writer.close()); // Reads should fail since the read end is closed. AWAIT_FAILED(reader.read()); }
TEST(CoordinatorTest, Failover) { const std::string path1 = utils::os::getcwd() + "/.log1"; const std::string path2 = utils::os::getcwd() + "/.log2"; utils::os::rmdir(path1); utils::os::rmdir(path2); Replica replica1(path1); Replica replica2(path2); Network network1; network1.add(replica1.pid()); network1.add(replica2.pid()); Coordinator coord1(2, &replica1, &network1); { Result<uint64_t> result = coord1.elect(Timeout(1.0)); ASSERT_TRUE(result.isSome()); EXPECT_EQ(0, result.get()); } uint64_t position; { Result<uint64_t> result = coord1.append("hello world", Timeout(1.0)); ASSERT_TRUE(result.isSome()); position = result.get(); EXPECT_EQ(1, position); } Network network2; network2.add(replica1.pid()); network2.add(replica2.pid()); Coordinator coord2(2, &replica2, &network2); { Result<uint64_t> result = coord2.elect(Timeout(1.0)); ASSERT_TRUE(result.isSome()); EXPECT_EQ(position, result.get()); } { Future<std::list<Action> > actions = replica2.read(position, position); ASSERT_TRUE(actions.await(2.0)); ASSERT_TRUE(actions.isReady()); ASSERT_EQ(1, actions.get().size()); EXPECT_EQ(position, actions.get().front().position()); ASSERT_TRUE(actions.get().front().has_type()); ASSERT_EQ(Action::APPEND, actions.get().front().type()); EXPECT_EQ("hello world", actions.get().front().append().bytes()); } utils::os::rmdir(path1); utils::os::rmdir(path2); }
TEST(FutureTest, CallableOnce) { Promise<Nothing> promise; promise.set(Nothing()); Future<int> future = promise.future() .then(lambda::partial( [](std::unique_ptr<int>&& o) { return *o; }, std::unique_ptr<int>(new int(42)))); ASSERT_TRUE(future.isReady()); EXPECT_EQ(42, future.get()); int n = 0; future = promise.future() .onReady(lambda::partial( [&n](std::unique_ptr<int> o) { n += *o; }, std::unique_ptr<int>(new int(1)))) .onAny(lambda::partial( [&n](std::unique_ptr<int>&& o) { n += *o; }, std::unique_ptr<int>(new int(10)))) .onFailed(lambda::partial( [&n](const std::unique_ptr<int>& o) { n += *o; }, std::unique_ptr<int>(new int(100)))) .onDiscard(lambda::partial( [&n](std::unique_ptr<int>&& o) { n += *o; }, std::unique_ptr<int>(new int(1000)))) .onDiscarded(lambda::partial( [&n](std::unique_ptr<int>&& o) { n += *o; }, std::unique_ptr<int>(new int(10000)))) .then([&n]() { return n; }); ASSERT_TRUE(future.isReady()); EXPECT_EQ(11, future.get()); }