#include <map>
#include <memory>
+#include <set>
-#include <folly/SharedMutex.h>
#include <folly/Synchronized.h>
namespace folly {
class RequestData {
public:
virtual ~RequestData() = default;
+
// Avoid calling RequestContext::setContextData, setContextDataIfAbsent, or
// clearContextData from these callbacks. Doing so will cause deadlock. We
// could fix these deadlocks, but only at significant performance penalty, so
// just don't do it!
+
+ virtual bool hasCallback() = 0;
+ // Callback executed when setting RequestContext. Make sure your RequestData
+ // instance overrides the hasCallback method to return true otherwise
+ // the callback will not be executed
virtual void onSet() {}
+ // Callback executed when unsetting RequestContext. Make sure your RequestData
+ // instance overrides the hasCallback method to return true otherwise
+ // the callback will not be executed
virtual void onUnset() {}
};
-class RequestContext;
-
// If you do not call create() to create a unique request context,
// this default request context will always be returned, and is never
// copied between threads.
// Get the current context.
static RequestContext* get();
- // The following API may be used to set per-request data in a thread-safe way.
- // This access is still performance sensitive, so please ask if you need help
- // profiling any use of these functions.
+ // The following APIs are used to add, remove and access RequestData instance
+ // in the RequestContext instance, normally used for per-RequestContext
+ // tracking or callback on set and unset. These APIs are Thread-safe.
+ // These APIs are performance sensitive, so please ask if you need help
+ // profiling any use of these APIs.
+
+ // Add RequestData instance "data" to this RequestContext instance, with
+ // string identifier "val". If the same string identifier has already been
+ // used, will print a warning message for the first time, clear the existing
+ // RequestData instance for "val", and **not** add "data".
void setContextData(
const std::string& val,
std::unique_ptr<RequestData> data);
- // Unlike setContextData, this method does not panic if the key is already
- // present. Returns true iff the new value has been inserted.
+ // Add RequestData instance "data" to this RequestContext instance, with
+ // string identifier "val". If the same string identifier has already been
+ // used, return false and do nothing. Otherwise add "data" and return true.
bool setContextDataIfAbsent(
const std::string& val,
std::unique_ptr<RequestData> data);
+ // Remove the RequestData instance with string identifier "val", if it exists.
+ void clearContextData(const std::string& val);
+
+ // Returns true if and only if the RequestData instance with string identifier
+ // "val" exists in this RequestContext instnace.
bool hasContextData(const std::string& val) const;
+ // Get (constant) raw pointer of the RequestData instance with string
+ // identifier "val" if it exists, otherwise returns null pointer.
RequestData* getContextData(const std::string& val);
const RequestData* getContextData(const std::string& val) const;
void onSet();
void onUnset();
- void clearContextData(const std::string& val);
-
// The following API is used to pass the context through queues / threads.
// saveContext is called to get a shared_ptr to the context, and
// setContext is used to reset it on the other side of the queue.
private:
static std::shared_ptr<RequestContext>& getStaticContext();
- using Data = std::map<std::string, std::unique_ptr<RequestData>>;
- folly::Synchronized<Data, folly::SharedMutex> data_;
+ bool doSetContextData(
+ const std::string& val,
+ std::unique_ptr<RequestData>& data,
+ bool strict);
+
+ struct State {
+ std::map<std::string, std::unique_ptr<RequestData>> requestData_;
+ std::set<RequestData*> callbackData_;
+ };
+ folly::Synchronized<State> state_;
};
class RequestContextScopeGuard {
// Set a RequestContext that was previously captured by saveContext(). It will
// be automatically reset to the original value when this goes out of scope.
explicit RequestContextScopeGuard(std::shared_ptr<RequestContext> ctx)
- : prev_(RequestContext::setContext(std::move(ctx))) {
- }
+ : prev_(RequestContext::setContext(std::move(ctx))) {}
~RequestContextScopeGuard() {
RequestContext::setContext(std::move(prev_));