optimize query execution

This commit is contained in:
BlackMATov
2024-12-01 17:31:53 +07:00
parent 68c4f6e89f
commit 99e1e06672
+73 -35
View File
@@ -10,10 +10,17 @@ local registry = {}
---
local __guids = idpools.idpool()
local __roots = {} ---@type table<evolved.entity, evolved.chunk>
local __chunks = {} ---@type table<evolved.entity, evolved.chunk[]>
local __changes = 0 ---@type integer
---@alias evolved.execution_stack evolved.chunk[]
---@alias evolved.execution_state [evolved.query, evolved.execution_stack, integer, integer]
---@alias evolved.execution_iterator fun(execute_state: evolved.execution_state?): evolved.chunk?
local __execution_state_cache = {} ---@type evolved.execution_state[]
---
---
---
@@ -326,6 +333,62 @@ local function __chunk_without_fragments(chunk, ...)
return chunk
end
---@param query evolved.query
---@return evolved.execution_state
---@nodiscard
local function __execution_state_acquire(query)
local state_cache = __execution_state_cache
if #state_cache == 0 then return { query, {}, __changes, query.__changes } end
local state = state_cache[#state_cache]
state_cache[#state_cache] = nil
state[1], state[3], state[4] = query, __changes, query.__changes
return state
end
---@param state evolved.execution_state
local function __execution_state_release(state)
state[1] = nil -- release query for garbage collection
assert(#state[2] == 0, 'execution stack should be empty')
__execution_state_cache[#__execution_state_cache + 1] = state
end
---@type evolved.execution_iterator
local function __execute_iterator(execution_state)
if execution_state == nil then return nil end
local query, execution_stack = execution_state[1], execution_state[2]
local chunk_changes, query_changes = execution_state[3], execution_state[4]
if chunk_changes ~= __changes then
error('chunks have been modified during query execution', 2)
end
if query_changes ~= query.__changes then
error('query has been modified during query execution', 2)
end
while #execution_stack > 0 do
local matched_chunk = execution_stack[#execution_stack]
execution_stack[#execution_stack] = nil
for _, matched_chunk_child in ipairs(matched_chunk.__children) do
if not query.__exclude_set[matched_chunk_child.__fragment] then
execution_stack[#execution_stack + 1] = matched_chunk_child
end
end
if #matched_chunk.__entities > 0 then
return matched_chunk
end
end
__execution_state_release(execution_state)
end
---
---
---
@@ -992,61 +1055,36 @@ function registry.exclude(query, ...)
end
---@param query evolved.query
---@return fun(): evolved.chunk?
---@return evolved.execution_iterator
---@return evolved.execution_state?
---@nodiscard
function registry.execute(query)
local include_list, exclude_list, exclude_set =
query.__include_list, query.__exclude_list, query.__exclude_set
local include_list, exclude_list =
query.__include_list, query.__exclude_list
if #include_list == 0 then
return function() end
return __execute_iterator
end
local main_fragment = include_list[#include_list]
local main_fragment_chunks = __chunks[main_fragment]
if main_fragment_chunks == nil or #main_fragment_chunks == 0 then
return function() end
return __execute_iterator
end
---@type evolved.chunk[]
local matched_chunk_stack = {}
local execution_state = __execution_state_acquire(query)
local execution_stack = execution_state[2]
for _, main_fragment_chunk in ipairs(main_fragment_chunks) do
if __chunk_has_all_fragment_list(main_fragment_chunk, include_list) then
if not __chunk_has_any_fragment_list(main_fragment_chunk, exclude_list) then
matched_chunk_stack[#matched_chunk_stack + 1] = main_fragment_chunk
execution_stack[#execution_stack + 1] = main_fragment_chunk
end
end
end
local chunk_changes = __changes
local query_changes = query.__changes
return function()
if chunk_changes ~= __changes then
error('chunks have been modified during query execution', 2)
end
if query_changes ~= query.__changes then
error('query has been modified during query execution', 2)
end
while #matched_chunk_stack > 0 do
local matched_chunk = matched_chunk_stack[#matched_chunk_stack]
matched_chunk_stack[#matched_chunk_stack] = nil
for _, matched_chunk_child in ipairs(matched_chunk.__children) do
if not exclude_set[matched_chunk_child.__fragment] then
matched_chunk_stack[#matched_chunk_stack + 1] = matched_chunk_child
end
end
if #matched_chunk.__entities > 0 then
return matched_chunk
end
end
end
return __execute_iterator, execution_state
end
---@param fragment evolved.entity