| 35 | } |
| 36 | |
| 37 | static void scheduleFrontierTask(ExecutionContext* context, const GraphRelInfo& relInfo, |
| 38 | Graph* graph, ExtendDirection extendDirection, const GDSComputeState& computeState, |
| 39 | std::vector<std::string> propertiesToScan) { |
| 40 | auto clientContext = context->clientContext; |
| 41 | auto task = getFrontierTask(clientContext, relInfo, graph, extendDirection, computeState, |
| 42 | std::move(propertiesToScan)); |
| 43 | if (computeState.frontierPair->getState() == GDSDensityState::SPARSE) { |
| 44 | task->runSparse(); |
| 45 | return; |
| 46 | } |
| 47 | |
| 48 | // GDSUtils::runFrontiersUntilConvergence is called from a GDSCall operator, which is |
| 49 | // already executed by a worker thread Tm of the task scheduler. So this function is |
| 50 | // executed by Tm. Because this function will monitor the task and wait for it to |
| 51 | // complete, running GDS algorithms effectively "loses" Tm. This can even lead to the |
| 52 | // query processor to halt, e.g., if there is a single worker thread in the system, and |
| 53 | // more generally decrease the number of worker threads by 1. Therefore, we instruct |
| 54 | // scheduleTaskAndWaitOrError to start a new thread by passing true as the last |
| 55 | // argument. |
| 56 | TaskScheduler::Get(*context->clientContext) |
| 57 | ->scheduleTaskAndWaitOrError(task, context, true /* launchNewWorkerThread */); |
| 58 | } |
| 59 | |
| 60 | static void runOneIteration(ExecutionContext* context, Graph* graph, |
| 61 | ExtendDirection extendDirection, const GDSComputeState& compState, |
no test coverage detected