Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-59509

Scheduling on ScopedTaskExecutor after underlying executor is shutdown invariants

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Open
    • Priority: Major - P3
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: Backlog
    • Component/s: None
    • Operating System:
      ALL
    • Steps To Reproduce:
      Hide

      Minimal repro, add this to scoped_task_executor_test.cpp:

      TEST_F(ScopedTaskExecutorTest, ShutdownUnderlyingThenSchedule) {
          ScopedTaskExecutor exec(getUnderlying());
          getUnderlying()->shutdown();
          int x = 2;
          exec->schedule([&](Status) { x += 2; });
      }

      Show
      Minimal repro, add this to scoped_task_executor_test.cpp: TEST_F(ScopedTaskExecutorTest, ShutdownUnderlyingThenSchedule) { ScopedTaskExecutor exec(getUnderlying()); getUnderlying()->shutdown(); int x = 2 ; exec->schedule([&](Status) { x += 2 ; }); }

      Description

      The ScopedTaskExecutor wraps another "underlying" TaskExecutor that it forwards work to actually be executed on. When work is scheduled on the ScopedTaskExecutor after the underlying executor is shutdown, this invariant in TaskExecutor::schedule is triggered.

       

      Here's a brief explanation as to why: say exec is a ScopedTaskExecutor. When exec->schedule(...) is called:

      1) The member-of-pointer operator on ScopedTaskExecutor returns a TaskExecutor*, which actually points to a ScopedTaskExecutor::Impl, which inherits from TaskExecutor. 

      2) TaskExecutor::schedule is called, and then calls the member scheduleWork; because the actual type here is ScopedTaskExecutor::Impl, we use its definition of scheduleWork here

      3) The ScopedTaskExecutor attempts to wrap the provided Task in a lambda here, where it captures the provided Task by forwarding it into the lambda. This will invoke the move assignment operator and invalidate the provided Task 

      4) The ScopedTaskExecutor attempts to schedule the wrapped Task on the underlying executor, which refuses because it is shutdown, and returns a bad status.

      5) The ScopedTaskExecutor propagates the bad status up to TaskExecutor::schedule. However, it has broken the contract of scheduleWork, by returning a bad status (failing to schedule) and invalidating the provided Task. Therefore, the invariant is hit. 

        Attachments

          Activity

            People

            Assignee:
            backlog-server-servicearch Backlog - Service Architecture
            Reporter:
            george.wangensteen George Wangensteen
            Participants:
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Dates

              Created:
              Updated: