Commit 3d61f8ac authored by Dave Watson's avatar Dave Watson Committed by Facebook Github Bot

Revert D8397670 D8797823

Summary:
Delayed hazptr destruction is causing destruction ordering issues.

P59812860$445

buck test //titan/cachius/test:CachiusServiceHandlerTest

Reviewed By: phil-lopreiato

Differential Revision: D8825716

fbshipit-source-id: 808341489fd80b8edb63eb7c12377a8ffadfd1eb
parent 2c76542e
...@@ -21,51 +21,18 @@ ...@@ -21,51 +21,18 @@
#include <folly/MapUtil.h> #include <folly/MapUtil.h>
#include <folly/SingletonThreadLocal.h> #include <folly/SingletonThreadLocal.h>
#include <folly/synchronization/CallOnce.h>
#include <folly/synchronization/Hazptr.h>
namespace folly { namespace folly {
namespace {
/*
* Some requests may not be deleted until long after main when the
* default hazptr_domain destructs. This may cause destruction
* ordering issues. Instead, cleanup as soon as possible after main
* using atexit.
*/
folly::once_flag atexitflag;
void cleanup(void) {
atexit([]() { hazptr_cleanup(); });
}
} // namespace
struct RequestContext::State : hazptr_obj_base<State> {
std::map<std::string, std::shared_ptr<RequestData>> requestData_;
std::set<RequestData*> callbackData_;
};
RequestContext::RequestContext() : state_(new State) {}
RequestContext::~RequestContext() {
auto p = state_.load(std::memory_order_relaxed);
delete p;
}
bool RequestContext::doSetContextData( bool RequestContext::doSetContextData(
const std::string& val, const std::string& val,
std::unique_ptr<RequestData>& data, std::unique_ptr<RequestData>& data,
bool strict) { bool strict) {
State* p{nullptr}; auto ulock = state_.ulock();
{
std::lock_guard<std::mutex> g(m_);
p = state_.load(std::memory_order_acquire);
bool conflict = false; bool conflict = false;
auto it = p->requestData_.find(val); auto it = ulock->requestData_.find(val);
if (it != p->requestData_.end()) { if (it != ulock->requestData_.end()) {
if (strict) { if (strict) {
return false; return false;
} else { } else {
...@@ -75,31 +42,23 @@ bool RequestContext::doSetContextData( ...@@ -75,31 +42,23 @@ bool RequestContext::doSetContextData(
} }
} }
auto newstate = new State(*p); auto wlock = ulock.moveFromUpgradeToWrite();
it = newstate->requestData_.find(val);
if (conflict) { if (conflict) {
if (it->second) { if (it->second) {
if (it->second->hasCallback()) { if (it->second->hasCallback()) {
it->second->onUnset(); it->second->onUnset();
newstate->callbackData_.erase(it->second.get()); wlock->callbackData_.erase(it->second.get());
} }
it->second.reset(); it->second.reset(nullptr);
} }
return true;
} }
if (data && data->hasCallback()) { if (data && data->hasCallback()) {
newstate->callbackData_.insert(data.get()); wlock->callbackData_.insert(data.get());
data->onSet(); data->onSet();
} }
newstate->requestData_[val] = std::move(data); wlock->requestData_[val] = std::move(data);
state_.store(newstate, std::memory_order_release);
}
if (p) {
p->retire();
folly::call_once(atexitflag, cleanup);
}
return true; return true;
} }
...@@ -117,49 +76,38 @@ bool RequestContext::setContextDataIfAbsent( ...@@ -117,49 +76,38 @@ bool RequestContext::setContextDataIfAbsent(
} }
bool RequestContext::hasContextData(const std::string& val) const { bool RequestContext::hasContextData(const std::string& val) const {
hazptr_local<1> hptr; return state_.rlock()->requestData_.count(val);
auto p = hptr[0].get_protected(state_);
return p->requestData_.count(val) != 0;
} }
RequestData* RequestContext::getContextData(const std::string& val) { RequestData* RequestContext::getContextData(const std::string& val) {
const std::shared_ptr<RequestData> dflt{nullptr}; const std::unique_ptr<RequestData> dflt{nullptr};
hazptr_local<1> hptr; return get_ref_default(state_.rlock()->requestData_, val, dflt).get();
auto p = hptr[0].get_protected(state_);
p->requestData_.count(val);
return get_ref_default(p->requestData_, val, dflt).get();
} }
const RequestData* RequestContext::getContextData( const RequestData* RequestContext::getContextData(
const std::string& val) const { const std::string& val) const {
const std::shared_ptr<RequestData> dflt{nullptr}; const std::unique_ptr<RequestData> dflt{nullptr};
hazptr_local<1> hptr; return get_ref_default(state_.rlock()->requestData_, val, dflt).get();
auto p = hptr[0].get_protected(state_);
p->requestData_.count(val);
return get_ref_default(p->requestData_, val, dflt).get();
} }
void RequestContext::onSet() { void RequestContext::onSet() {
hazptr_holder<> hptr; auto rlock = state_.rlock();
auto p = hptr.get_protected(state_); for (const auto& data : rlock->callbackData_) {
for (const auto& data : p->callbackData_) {
data->onSet(); data->onSet();
} }
} }
void RequestContext::onUnset() { void RequestContext::onUnset() {
hazptr_holder<> hptr; auto rlock = state_.rlock();
auto p = hptr.get_protected(state_); for (const auto& data : rlock->callbackData_) {
for (const auto& data : p->callbackData_) {
data->onUnset(); data->onUnset();
} }
} }
std::shared_ptr<RequestContext> RequestContext::createChild() { std::shared_ptr<RequestContext> RequestContext::createChild() {
hazptr_local<1> hptr;
auto p = hptr[0].get_protected(state_);
auto child = std::make_shared<RequestContext>(); auto child = std::make_shared<RequestContext>();
for (const auto& entry : p->requestData_) { auto rlock = state_.rlock();
for (const auto& entry : rlock->requestData_) {
auto& key = entry.first; auto& key = entry.first;
auto childData = entry.second->createChild(); auto childData = entry.second->createChild();
if (childData) { if (childData) {
...@@ -170,38 +118,24 @@ std::shared_ptr<RequestContext> RequestContext::createChild() { ...@@ -170,38 +118,24 @@ std::shared_ptr<RequestContext> RequestContext::createChild() {
} }
void RequestContext::clearContextData(const std::string& val) { void RequestContext::clearContextData(const std::string& val) {
std::shared_ptr<RequestData> requestData; std::unique_ptr<RequestData> requestData;
// requestData is deleted while lock is not held, in case // Delete the RequestData after giving up the wlock just in case one of the
// destructor contains calls to RequestContext // RequestData destructors will try to grab the lock again.
State* p{nullptr};
{ {
std::lock_guard<std::mutex> g(m_); auto ulock = state_.ulock();
p = state_.load(std::memory_order_acquire); auto it = ulock->requestData_.find(val);
if (it == ulock->requestData_.end()) {
auto it = p->requestData_.find(val);
if (it == p->requestData_.end()) {
return; return;
} }
auto newstate = new State(*p); auto wlock = ulock.moveFromUpgradeToWrite();
it = newstate->requestData_.find(val);
CHECK(it != newstate->requestData_.end());
if (it->second && it->second->hasCallback()) { if (it->second && it->second->hasCallback()) {
it->second->onUnset(); it->second->onUnset();
newstate->callbackData_.erase(it->second.get()); wlock->callbackData_.erase(it->second.get());
}
requestData = it->second;
newstate->requestData_.erase(it);
state_.store(newstate, std::memory_order_release);
} }
if (p) { requestData = std::move(it->second);
p->retire(); wlock->requestData_.erase(it);
folly::call_once(atexitflag, cleanup);
} }
} }
......
...@@ -16,12 +16,12 @@ ...@@ -16,12 +16,12 @@
#pragma once #pragma once
#include <atomic>
#include <map> #include <map>
#include <memory> #include <memory>
#include <mutex>
#include <set> #include <set>
#include <folly/Synchronized.h>
namespace folly { namespace folly {
// Some request context that follows an async request through a process // Some request context that follows an async request through a process
...@@ -58,8 +58,6 @@ class RequestData { ...@@ -58,8 +58,6 @@ class RequestData {
// copied between threads. // copied between threads.
class RequestContext { class RequestContext {
public: public:
RequestContext();
~RequestContext();
// Create a unique request context for this request. // Create a unique request context for this request.
// It will be passed between queues / threads (where implemented), // It will be passed between queues / threads (where implemented),
// so it should be valid for the lifetime of the request. // so it should be valid for the lifetime of the request.
...@@ -133,9 +131,11 @@ class RequestContext { ...@@ -133,9 +131,11 @@ class RequestContext {
std::unique_ptr<RequestData>& data, std::unique_ptr<RequestData>& data,
bool strict); bool strict);
struct State; struct State {
std::atomic<State*> state_; std::map<std::string, std::unique_ptr<RequestData>> requestData_;
std::mutex m_; std::set<RequestData*> callbackData_;
};
folly::Synchronized<State> state_;
}; };
class RequestContextScopeGuard { class RequestContextScopeGuard {
......
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