@@ -1848,6 +1848,31 @@ void* EventuallyPersistentEngine::getEngineSpecific(const CookieIface* cookie) {
18481848 return cookie->getEngineStorage ();
18491849}
18501850
1851+ void EventuallyPersistentEngine::storeStatTask (
1852+ const CookieIface* cookie, std::shared_ptr<BackgroundStatTask> task) {
1853+ // store a ptr to a shared_ptr to the task (must ensure the task is not
1854+ // destroyed before the connection retrieves the result).
1855+ // Once the frontend thread is notified, it must call retrieveStatTask,
1856+ // which will free the heap-allocated shared_ptr.
1857+ auto wrapper = std::make_unique<std::shared_ptr<BackgroundStatTask>>(task);
1858+ storeEngineSpecific (cookie, wrapper.release ());
1859+ }
1860+
1861+ std::shared_ptr<BackgroundStatTask>
1862+ EventuallyPersistentEngine::retrieveStatTask (const CookieIface* cookie) {
1863+ void * data = getEngineSpecific (cookie);
1864+ if (data) {
1865+ // take back ownership of the task ptr
1866+ auto ptr = std::unique_ptr<std::shared_ptr<BackgroundStatTask>>(
1867+ reinterpret_cast <std::shared_ptr<BackgroundStatTask>*>(data));
1868+ // clear the engine specific - it's not valid to retrieve the
1869+ // task twice (would lead to a double free)
1870+ storeEngineSpecific (cookie, nullptr );
1871+ return *ptr;
1872+ }
1873+ return nullptr ;
1874+ }
1875+
18511876bool EventuallyPersistentEngine::isDatatypeSupported (
18521877 const CookieIface* cookie, protocol_binary_datatype_t datatype) {
18531878 return cookie->isDatatypeSupported (datatype);
@@ -3756,23 +3781,20 @@ class StatCheckpointVisitor : public VBucketVisitor {
37563781 AddStatFn add_stat;
37573782};
37583783
3759-
3760- class StatCheckpointTask : public GlobalTask {
3784+ class StatCheckpointTask : public BackgroundStatTask {
37613785public:
37623786 StatCheckpointTask (EventuallyPersistentEngine* e,
37633787 const CookieIface* c,
37643788 AddStatFn a)
3765- : GlobalTask(e, TaskId::StatCheckpointTask, 0 , false ),
3766- ep (e),
3767- cookie(c),
3768- add_stat(std::move(a)) {
3789+ : BackgroundStatTask(e, c, TaskId::StatCheckpointTask) {
37693790 }
3770- bool run () override {
3791+
3792+ cb::engine_errc collectStats () override {
37713793 TRACE_EVENT0 (" ep-engine/task" , " StatsCheckpointTask" );
3772- StatCheckpointVisitor scv (ep-> getKVBucket (), cookie, add_stat);
3773- ep ->getKVBucket ()-> visit (scv );
3774- ep-> notifyIOComplete (cookie, cb::engine_errc::success );
3775- return false ;
3794+ StatCheckpointVisitor scv (
3795+ e ->getKVBucket (), cookie, getDeferredAddStat () );
3796+ e-> getKVBucket ()-> visit (scv );
3797+ return cb::engine_errc::success ;
37763798 }
37773799
37783800 std::string getDescription () const override {
@@ -3785,11 +3807,6 @@ class StatCheckpointTask : public GlobalTask {
37853807 // take /too/ long, so set limit of 100ms.
37863808 return std::chrono::milliseconds (100 );
37873809 }
3788-
3789- private:
3790- EventuallyPersistentEngine *ep;
3791- const CookieIface* cookie;
3792- AddStatFn add_stat;
37933810};
37943811// / @endcond
37953812
@@ -3799,15 +3816,14 @@ cb::engine_errc EventuallyPersistentEngine::doCheckpointStats(
37993816 const char * stat_key,
38003817 int nkey) {
38013818 if (nkey == 10 ) {
3802- void * es = getEngineSpecific (cookie);
3803- if (es == nullptr ) {
3804- ExTask task = std::make_shared<StatCheckpointTask>(
3805- this , cookie, add_stat);
3819+ auto task = retrieveStatTask (cookie);
3820+ if (!task) {
3821+ task = std::make_shared<StatCheckpointTask>(this , cookie, add_stat);
38063822 ExecutorPool::get ()->schedule (task);
3807- storeEngineSpecific (cookie, this );
3823+ storeStatTask (cookie, task );
38083824 return cb::engine_errc::would_block;
38093825 } else {
3810- storeEngineSpecific (cookie, nullptr );
3826+ return task-> maybeWriteResponse (add_stat );
38113827 }
38123828 } else if (nkey > 11 ) {
38133829 std::string vbid (&stat_key[11 ], nkey - 11 );
@@ -4034,21 +4050,19 @@ static void showConnAggStat(const std::string& connType,
40344050 }
40354051}
40364052
4037- class StatDCPTask : public GlobalTask {
4053+ class StatDCPTask : public BackgroundStatTask {
40384054public:
40394055 using Callback = std::function<cb::engine_errc(
40404056 EventuallyPersistentEngine* e, const CookieIface* cookie)>;
40414057 StatDCPTask (EventuallyPersistentEngine* e,
40424058 const CookieIface* cookie,
40434059 std::string_view description,
40444060 Callback callback)
4045- : GlobalTask(e, TaskId::StatDCPTask, 0 , false ),
4046- e(e),
4047- cookie(cookie),
4061+ : BackgroundStatTask(e, cookie, TaskId::StatDCPTask),
40484062 description(description),
40494063 callback(std::move(callback)) {
40504064 }
4051- bool run () override {
4065+ cb::engine_errc collectStats () override {
40524066 TRACE_EVENT0 (" ep-engine/task" , " StatDCPTask" );
40534067 cb::engine_errc result = cb::engine_errc::failed;
40544068 try {
@@ -4060,8 +4074,7 @@ class StatDCPTask : public GlobalTask {
40604074 e.what (),
40614075 getDescription ());
40624076 }
4063- e->notifyIOComplete (cookie, result);
4064- return false ;
4077+ return result;
40654078 }
40664079
40674080 std::string getDescription () const override {
@@ -4075,8 +4088,6 @@ class StatDCPTask : public GlobalTask {
40754088 }
40764089
40774090private:
4078- EventuallyPersistentEngine* e;
4079- const CookieIface* cookie;
40804091 const std::string description;
40814092 Callback callback;
40824093};
@@ -4085,9 +4096,9 @@ cb::engine_errc EventuallyPersistentEngine::doConnAggStats(
40854096 const CookieIface* cookie,
40864097 const AddStatFn& add_stat,
40874098 std::string_view sep) {
4088- void * engineSpecific = getEngineSpecific (cookie);
4089- if (engineSpecific == nullptr ) {
4090- ExTask task = std::make_shared<StatDCPTask>(
4099+ auto task = retrieveStatTask (cookie);
4100+ if (!task ) {
4101+ task = std::make_shared<StatDCPTask>(
40914102 this ,
40924103 cookie,
40934104 " Aggregated DCP stats" ,
@@ -4100,13 +4111,11 @@ cb::engine_errc EventuallyPersistentEngine::doConnAggStats(
41004111 return cb::engine_errc::success;
41014112 });
41024113 ExecutorPool::get ()->schedule (task);
4103- storeEngineSpecific (cookie, this );
4114+ storeStatTask (cookie, task );
41044115 return cb::engine_errc::would_block;
41054116 } else {
4106- storeEngineSpecific (cookie, nullptr );
4117+ return task-> maybeWriteResponse (add_stat );
41074118 }
4108-
4109- return cb::engine_errc::success;
41104119}
41114120
41124121cb::engine_errc EventuallyPersistentEngine::doConnAggStatsInner (
@@ -4137,9 +4146,9 @@ cb::engine_errc EventuallyPersistentEngine::doDcpStats(
41374146 const CookieIface* cookie,
41384147 const AddStatFn& add_stat,
41394148 std::string_view value) {
4140- void * engineSpecific = getEngineSpecific (cookie);
4141- if (engineSpecific == nullptr ) {
4142- ExTask task = std::make_shared<StatDCPTask>(
4149+ auto task = retrieveStatTask (cookie);
4150+ if (!task ) {
4151+ task = std::make_shared<StatDCPTask>(
41434152 this ,
41444153 cookie,
41454154 " Summarised bucket-wide DCP stats" ,
@@ -4150,13 +4159,11 @@ cb::engine_errc EventuallyPersistentEngine::doDcpStats(
41504159 return cb::engine_errc::success;
41514160 });
41524161 ExecutorPool::get ()->schedule (task);
4153- storeEngineSpecific (cookie, this );
4162+ storeStatTask (cookie, task );
41544163 return cb::engine_errc::would_block;
41554164 } else {
4156- storeEngineSpecific (cookie, nullptr );
4165+ return task-> maybeWriteResponse (add_stat );
41574166 }
4158-
4159- return cb::engine_errc::success;
41604167}
41614168
41624169void EventuallyPersistentEngine::doDcpStatsInner (const CookieIface* cookie,
0 commit comments