_ExecuteQuery accepts a GraphQueryCtx as an argument it may be called directly by a reader thread or the Redis main thread, or dispatched as a worker thread job when used for writing.
| 284 | // it may be called directly by a reader thread or the Redis main thread, |
| 285 | // or dispatched as a worker thread job when used for writing. |
| 286 | static void _ExecuteQuery(void *args) { |
| 287 | ASSERT(args != NULL); |
| 288 | |
| 289 | GraphQueryCtx *gq_ctx = args; |
| 290 | QueryCtx *query_ctx = gq_ctx->query_ctx; |
| 291 | GraphContext *gc = gq_ctx->graph_ctx; |
| 292 | RedisModuleCtx *rm_ctx = gq_ctx->rm_ctx; |
| 293 | ExecutionCtx *exec_ctx = gq_ctx->exec_ctx; |
| 294 | CommandCtx *command_ctx = gq_ctx->command_ctx; |
| 295 | AST *ast = exec_ctx->ast; |
| 296 | ExecutionPlan *plan = exec_ctx->plan; |
| 297 | ExecutionType exec_type = exec_ctx->exec_type; |
| 298 | const bool profile = (query_ctx->flags & QueryExecutionTypeFlag_PROFILE); |
| 299 | const bool readonly = !(query_ctx->flags & QueryExecutionTypeFlag_WRITE); |
| 300 | |
| 301 | // if we have migrated to a writer thread, |
| 302 | // update thread-local storage and track the CommandCtx |
| 303 | if (command_ctx->thread == EXEC_THREAD_WRITER) { |
| 304 | // transition the query from waiting to executing |
| 305 | QueryCtx_AdvanceStage(query_ctx); |
| 306 | QueryCtx_SetTLS(query_ctx); |
| 307 | Globals_TrackCommandCtx(command_ctx); |
| 308 | } |
| 309 | |
| 310 | // instantiate the query ResultSet |
| 311 | bool compact = command_ctx->compact; |
| 312 | // replicated command don't need to return result |
| 313 | ResultSetFormatterType resultset_format = |
| 314 | profile || command_ctx->replicated_command |
| 315 | ? FORMATTER_NOP |
| 316 | : (compact) |
| 317 | ? FORMATTER_COMPACT |
| 318 | : FORMATTER_VERBOSE; |
| 319 | ResultSet *result_set = NewResultSet(rm_ctx, resultset_format); |
| 320 | if(exec_ctx->cached) { |
| 321 | ResultSet_CachedExecution(result_set); // indicate a cached execution |
| 322 | } |
| 323 | |
| 324 | QueryCtx_SetResultSet(result_set); |
| 325 | |
| 326 | // acquire the appropriate lock |
| 327 | if(readonly) { |
| 328 | Graph_AcquireReadLock(gc->g); |
| 329 | } else { |
| 330 | // if this is a writer query `we need to re-open the graph key with write flag |
| 331 | // this notifies Redis that the key is "dirty" any watcher on that key will |
| 332 | // be notified |
| 333 | CommandCtx_ThreadSafeContextLock(command_ctx); |
| 334 | { |
| 335 | GraphContext_MarkWriter(rm_ctx, gc); |
| 336 | } |
| 337 | CommandCtx_ThreadSafeContextUnlock(command_ctx); |
| 338 | } |
| 339 | |
| 340 | if(exec_type == EXECUTION_TYPE_QUERY) { // query operation |
| 341 | // set policy after lock acquisition, |
| 342 | // avoid resetting policies between readers and writers |
| 343 | Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_FLUSH_RESIZE); |
no test coverage detected