Commit cc671d29 authored by Andrii Grynenko's avatar Andrii Grynenko Committed by Sara Golemon

RequestContext support

Summary: Integrating RequestContext into fibers library. RequestContext is saved for every task, when that task is created. If RequestContext is overriden when a task is being run (within fiber, in runInMainContext, within function passed to await call) the new context will continue to be used for the task.

Reviewed By: @alikhtarov

Differential Revision: D2240152
parent 5016d8c7
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <folly/CPortability.h> #include <folly/CPortability.h>
#include <folly/IntrusiveList.h> #include <folly/IntrusiveList.h>
#include <folly/experimental/fibers/BoostContextCompatibility.h> #include <folly/experimental/fibers/BoostContextCompatibility.h>
#include <folly/io/async/Request.h>
#include <folly/Portability.h> #include <folly/Portability.h>
namespace folly { namespace fibers { namespace folly { namespace fibers {
...@@ -102,6 +103,7 @@ class Fiber { ...@@ -102,6 +103,7 @@ class Fiber {
FiberManager& fiberManager_; /**< Associated FiberManager */ FiberManager& fiberManager_; /**< Associated FiberManager */
FContext fcontext_; /**< current task execution context */ FContext fcontext_; /**< current task execution context */
intptr_t data_; /**< Used to keep some data with the Fiber */ intptr_t data_; /**< Used to keep some data with the Fiber */
std::shared_ptr<RequestContext> rcontext_; /**< current RequestContext */
std::function<void()> func_; /**< task function */ std::function<void()> func_; /**< task function */
bool recordStackUsed_{false}; bool recordStackUsed_{false};
bool stackFilledWithMagic_{false}; bool stackFilledWithMagic_{false};
......
...@@ -66,6 +66,7 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) { ...@@ -66,6 +66,7 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) {
assert(fiber->state_ == Fiber::NOT_STARTED || assert(fiber->state_ == Fiber::NOT_STARTED ||
fiber->state_ == Fiber::READY_TO_RUN); fiber->state_ == Fiber::READY_TO_RUN);
currentFiber_ = fiber; currentFiber_ = fiber;
fiber->rcontext_ = RequestContext::setContext(std::move(fiber->rcontext_));
if (observer_) { if (observer_) {
observer_->starting(reinterpret_cast<uintptr_t>(fiber)); observer_->starting(reinterpret_cast<uintptr_t>(fiber));
} }
...@@ -92,6 +93,7 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) { ...@@ -92,6 +93,7 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) {
observer_->stopped(reinterpret_cast<uintptr_t>(fiber)); observer_->stopped(reinterpret_cast<uintptr_t>(fiber));
} }
currentFiber_ = nullptr; currentFiber_ = nullptr;
fiber->rcontext_ = RequestContext::setContext(std::move(fiber->rcontext_));
} else if (fiber->state_ == Fiber::INVALID) { } else if (fiber->state_ == Fiber::INVALID) {
assert(fibersActive_ > 0); assert(fibersActive_ > 0);
--fibersActive_; --fibersActive_;
...@@ -113,7 +115,9 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) { ...@@ -113,7 +115,9 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) {
observer_->stopped(reinterpret_cast<uintptr_t>(fiber)); observer_->stopped(reinterpret_cast<uintptr_t>(fiber));
} }
currentFiber_ = nullptr; currentFiber_ = nullptr;
fiber->rcontext_ = RequestContext::setContext(std::move(fiber->rcontext_));
fiber->localData_.reset(); fiber->localData_.reset();
fiber->rcontext_.reset();
if (fibersPoolSize_ < options_.maxFibersPoolSize) { if (fibersPoolSize_ < options_.maxFibersPoolSize) {
fibersPool_.push_front(*fiber); fibersPool_.push_front(*fiber);
...@@ -128,6 +132,7 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) { ...@@ -128,6 +132,7 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) {
observer_->stopped(reinterpret_cast<uintptr_t>(fiber)); observer_->stopped(reinterpret_cast<uintptr_t>(fiber));
} }
currentFiber_ = nullptr; currentFiber_ = nullptr;
fiber->rcontext_ = RequestContext::setContext(std::move(fiber->rcontext_));
fiber->state_ = Fiber::READY_TO_RUN; fiber->state_ = Fiber::READY_TO_RUN;
yieldedFibers_.push_back(*fiber); yieldedFibers_.push_back(*fiber);
} }
...@@ -168,6 +173,7 @@ inline bool FiberManager::loopUntilNoReady() { ...@@ -168,6 +173,7 @@ inline bool FiberManager::loopUntilNoReady() {
if (task->localData) { if (task->localData) {
fiber->localData_ = *task->localData; fiber->localData_ = *task->localData;
} }
fiber->rcontext_ = std::move(task->rcontext);
fiber->setFunction(std::move(task->func)); fiber->setFunction(std::move(task->func));
fiber->data_ = reinterpret_cast<intptr_t>(fiber); fiber->data_ = reinterpret_cast<intptr_t>(fiber);
...@@ -471,6 +477,7 @@ inline void FiberManager::initLocalData(Fiber& fiber) { ...@@ -471,6 +477,7 @@ inline void FiberManager::initLocalData(Fiber& fiber) {
if (fm && fm->currentFiber_ && fm->localType_ == localType_) { if (fm && fm->currentFiber_ && fm->localType_ == localType_) {
fiber.localData_ = fm->currentFiber_->localData_; fiber.localData_ = fm->currentFiber_->localData_;
} }
fiber.rcontext_ = RequestContext::saveContext();
} }
template <typename LocalT> template <typename LocalT>
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <folly/Executor.h> #include <folly/Executor.h>
#include <folly/Likely.h> #include <folly/Likely.h>
#include <folly/IntrusiveList.h> #include <folly/IntrusiveList.h>
#include <folly/io/async/Request.h>
#include <folly/futures/Try.h> #include <folly/futures/Try.h>
#include <folly/experimental/ExecutionObserver.h> #include <folly/experimental/ExecutionObserver.h>
...@@ -252,13 +253,17 @@ class FiberManager : public ::folly::Executor { ...@@ -252,13 +253,17 @@ class FiberManager : public ::folly::Executor {
struct RemoteTask { struct RemoteTask {
template <typename F> template <typename F>
explicit RemoteTask(F&& f) : func(std::forward<F>(f)) {} explicit RemoteTask(F&& f) :
func(std::forward<F>(f)),
rcontext(RequestContext::saveContext()) {}
template <typename F> template <typename F>
RemoteTask(F&& f, const Fiber::LocalData& localData_) : RemoteTask(F&& f, const Fiber::LocalData& localData_) :
func(std::forward<F>(f)), func(std::forward<F>(f)),
localData(folly::make_unique<Fiber::LocalData>(localData_)) {} localData(folly::make_unique<Fiber::LocalData>(localData_)),
rcontext(RequestContext::saveContext()) {}
std::function<void()> func; std::function<void()> func;
std::unique_ptr<Fiber::LocalData> localData; std::unique_ptr<Fiber::LocalData> localData;
std::shared_ptr<RequestContext> rcontext;
AtomicLinkedListHook<RemoteTask> nextRemoteTask; AtomicLinkedListHook<RemoteTask> nextRemoteTask;
}; };
......
...@@ -1332,6 +1332,81 @@ TEST(FiberManager, yieldTest) { ...@@ -1332,6 +1332,81 @@ TEST(FiberManager, yieldTest) {
EXPECT_TRUE(checkRan); EXPECT_TRUE(checkRan);
} }
TEST(FiberManager, RequestContext) {
FiberManager fm(folly::make_unique<SimpleLoopController>());
auto& loopController =
dynamic_cast<SimpleLoopController&>(fm.loopController());
bool checkRun1 = false;
bool checkRun2 = false;
bool checkRun3 = false;
folly::fibers::Baton baton1;
folly::fibers::Baton baton2;
folly::fibers::Baton baton3;
folly::RequestContext::create();
auto rcontext1 = folly::RequestContext::get();
fm.addTask([&]() {
EXPECT_EQ(rcontext1, folly::RequestContext::get());
baton1.wait([&]() {
EXPECT_EQ(rcontext1, folly::RequestContext::get());
});
EXPECT_EQ(rcontext1, folly::RequestContext::get());
runInMainContext([&]() {
EXPECT_EQ(rcontext1, folly::RequestContext::get());
});
checkRun1 = true;
});
folly::RequestContext::create();
auto rcontext2 = folly::RequestContext::get();
fm.addTaskRemote([&]() {
EXPECT_EQ(rcontext2, folly::RequestContext::get());
baton2.wait();
EXPECT_EQ(rcontext2, folly::RequestContext::get());
checkRun2 = true;
});
folly::RequestContext::create();
auto rcontext3 = folly::RequestContext::get();
fm.addTaskFinally([&]() {
EXPECT_EQ(rcontext3, folly::RequestContext::get());
baton3.wait();
EXPECT_EQ(rcontext3, folly::RequestContext::get());
return folly::Unit();
},
[&](Try<folly::Unit>&& t) {
EXPECT_EQ(rcontext3, folly::RequestContext::get());
checkRun3 = true;
});
folly::RequestContext::create();
auto rcontext = folly::RequestContext::get();
fm.loopUntilNoReady();
EXPECT_EQ(rcontext, folly::RequestContext::get());
baton1.post();
EXPECT_EQ(rcontext, folly::RequestContext::get());
fm.loopUntilNoReady();
EXPECT_TRUE(checkRun1);
EXPECT_EQ(rcontext, folly::RequestContext::get());
baton2.post();
EXPECT_EQ(rcontext, folly::RequestContext::get());
fm.loopUntilNoReady();
EXPECT_TRUE(checkRun2);
EXPECT_EQ(rcontext, folly::RequestContext::get());
baton3.post();
EXPECT_EQ(rcontext, folly::RequestContext::get());
fm.loopUntilNoReady();
EXPECT_TRUE(checkRun3);
EXPECT_EQ(rcontext, folly::RequestContext::get());
}
static size_t sNumAwaits; static size_t sNumAwaits;
void runBenchmark(size_t numAwaits, size_t toSend) { void runBenchmark(size_t numAwaits, size_t toSend) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment