From: Andrii Grynenko Date: Tue, 14 Jul 2015 17:29:36 +0000 (-0700) Subject: RequestContext support X-Git-Tag: v0.51.0~15 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=cc671d294c2d51022348ec684109c7d11742ab50;p=folly.git 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 --- diff --git a/folly/experimental/fibers/Fiber.h b/folly/experimental/fibers/Fiber.h index c4dbec00..78624882 100644 --- a/folly/experimental/fibers/Fiber.h +++ b/folly/experimental/fibers/Fiber.h @@ -24,6 +24,7 @@ #include #include #include +#include #include namespace folly { namespace fibers { @@ -102,6 +103,7 @@ class Fiber { FiberManager& fiberManager_; /**< Associated FiberManager */ FContext fcontext_; /**< current task execution context */ intptr_t data_; /**< Used to keep some data with the Fiber */ + std::shared_ptr rcontext_; /**< current RequestContext */ std::function func_; /**< task function */ bool recordStackUsed_{false}; bool stackFilledWithMagic_{false}; diff --git a/folly/experimental/fibers/FiberManager-inl.h b/folly/experimental/fibers/FiberManager-inl.h index e0c7e578..dcf54634 100644 --- a/folly/experimental/fibers/FiberManager-inl.h +++ b/folly/experimental/fibers/FiberManager-inl.h @@ -66,6 +66,7 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) { assert(fiber->state_ == Fiber::NOT_STARTED || fiber->state_ == Fiber::READY_TO_RUN); currentFiber_ = fiber; + fiber->rcontext_ = RequestContext::setContext(std::move(fiber->rcontext_)); if (observer_) { observer_->starting(reinterpret_cast(fiber)); } @@ -92,6 +93,7 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) { observer_->stopped(reinterpret_cast(fiber)); } currentFiber_ = nullptr; + fiber->rcontext_ = RequestContext::setContext(std::move(fiber->rcontext_)); } else if (fiber->state_ == Fiber::INVALID) { assert(fibersActive_ > 0); --fibersActive_; @@ -113,7 +115,9 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) { observer_->stopped(reinterpret_cast(fiber)); } currentFiber_ = nullptr; + fiber->rcontext_ = RequestContext::setContext(std::move(fiber->rcontext_)); fiber->localData_.reset(); + fiber->rcontext_.reset(); if (fibersPoolSize_ < options_.maxFibersPoolSize) { fibersPool_.push_front(*fiber); @@ -128,6 +132,7 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) { observer_->stopped(reinterpret_cast(fiber)); } currentFiber_ = nullptr; + fiber->rcontext_ = RequestContext::setContext(std::move(fiber->rcontext_)); fiber->state_ = Fiber::READY_TO_RUN; yieldedFibers_.push_back(*fiber); } @@ -168,6 +173,7 @@ inline bool FiberManager::loopUntilNoReady() { if (task->localData) { fiber->localData_ = *task->localData; } + fiber->rcontext_ = std::move(task->rcontext); fiber->setFunction(std::move(task->func)); fiber->data_ = reinterpret_cast(fiber); @@ -471,6 +477,7 @@ inline void FiberManager::initLocalData(Fiber& fiber) { if (fm && fm->currentFiber_ && fm->localType_ == localType_) { fiber.localData_ = fm->currentFiber_->localData_; } + fiber.rcontext_ = RequestContext::saveContext(); } template diff --git a/folly/experimental/fibers/FiberManager.h b/folly/experimental/fibers/FiberManager.h index 847646d3..bb7b500b 100644 --- a/folly/experimental/fibers/FiberManager.h +++ b/folly/experimental/fibers/FiberManager.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -252,13 +253,17 @@ class FiberManager : public ::folly::Executor { struct RemoteTask { template - explicit RemoteTask(F&& f) : func(std::forward(f)) {} + explicit RemoteTask(F&& f) : + func(std::forward(f)), + rcontext(RequestContext::saveContext()) {} template RemoteTask(F&& f, const Fiber::LocalData& localData_) : func(std::forward(f)), - localData(folly::make_unique(localData_)) {} + localData(folly::make_unique(localData_)), + rcontext(RequestContext::saveContext()) {} std::function func; std::unique_ptr localData; + std::shared_ptr rcontext; AtomicLinkedListHook nextRemoteTask; }; diff --git a/folly/experimental/fibers/test/FibersTest.cpp b/folly/experimental/fibers/test/FibersTest.cpp index 878fc64c..3f323a20 100644 --- a/folly/experimental/fibers/test/FibersTest.cpp +++ b/folly/experimental/fibers/test/FibersTest.cpp @@ -1332,6 +1332,81 @@ TEST(FiberManager, yieldTest) { EXPECT_TRUE(checkRan); } +TEST(FiberManager, RequestContext) { + FiberManager fm(folly::make_unique()); + auto& loopController = + dynamic_cast(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&& 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; void runBenchmark(size_t numAwaits, size_t toSend) {