Skip to content

Commit 7b44740

Browse files
committed
deterministic chunk ordering
1 parent b0d035c commit 7b44740

2 files changed

Lines changed: 158 additions & 62 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,6 +1569,7 @@ builder_mt:destruction_policy :: id -> builder
15691569
### vX.Y.Z
15701570

15711571
- Performance improvements of the [`evolved.destroy`](#evolveddestroy) and [`evolved.batch_destroy`](#evolvedbatch_destroy) functions
1572+
- Ensured deterministic chunk ordering to improve processing consistency across runs
15721573

15731574
### v1.8.0
15741575

evolved.lua

Lines changed: 157 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,7 @@ end
768768

769769
local __list_new
770770
local __list_dup
771+
local __list_lwr
771772

772773
---@param reserve? integer
773774
---@return any[]
@@ -796,6 +797,42 @@ function __list_dup(list)
796797
return dup_list
797798
end
798799

800+
---@generic V
801+
---@param list V[]
802+
---@param item V
803+
---@param comp? fun(a: V, b: V): boolean
804+
---@return integer lower_bound_index
805+
---@nodiscard
806+
function __list_lwr(list, item, comp)
807+
local lower, upper = 1, #list
808+
809+
if comp then
810+
while lower <= upper do
811+
local middle = lower + (upper - lower) / 2
812+
middle = middle - middle % 1 -- fast math.floor
813+
814+
if comp(item, list[middle]) then
815+
upper = middle - 1
816+
else
817+
lower = middle + 1
818+
end
819+
end
820+
else
821+
while lower <= upper do
822+
local middle = lower + (upper - lower) / 2
823+
middle = middle - middle % 1 -- fast math.floor
824+
825+
if item < list[middle] then
826+
upper = middle - 1
827+
else
828+
lower = middle + 1
829+
end
830+
end
831+
end
832+
833+
return lower
834+
end
835+
799836
---
800837
---
801838
---
@@ -1111,6 +1148,11 @@ local __new_chunk
11111148
local __default_realloc
11121149
local __default_compmove
11131150

1151+
local __add_root_chunk
1152+
local __remove_root_chunk
1153+
local __add_child_chunk
1154+
local __remove_child_chunk
1155+
11141156
local __update_chunk_caches
11151157
local __update_chunk_queries
11161158
local __update_chunk_storages
@@ -1272,29 +1314,10 @@ function __new_chunk(chunk_parent, chunk_fragment)
12721314
__has_required_fragments = false,
12731315
}, __chunk_mt)
12741316

1275-
if chunk_parent then
1276-
chunk.__parent = chunk_parent
1277-
1278-
chunk_parent.__child_count = __assoc_list_insert_ex(
1279-
chunk_parent.__child_set, chunk_parent.__child_list, chunk_parent.__child_count,
1280-
chunk)
1281-
1282-
chunk_parent.__with_fragment_edges[chunk_fragment] = chunk
1283-
chunk.__without_fragment_edges[chunk_fragment] = chunk_parent
1284-
end
1285-
12861317
if not chunk_parent then
1287-
local existing_root_index = __root_set[chunk_fragment]
1288-
local existing_root_chunk = __root_list[existing_root_index]
1289-
1290-
if existing_root_chunk ~= nil then
1291-
__error_fmt('unexpected root chunk (%s)',
1292-
__lua_tostring(existing_root_chunk))
1293-
end
1294-
1295-
__root_count = __root_count + 1
1296-
__root_set[chunk_fragment] = __root_count
1297-
__root_list[__root_count] = chunk
1318+
__add_root_chunk(chunk)
1319+
else
1320+
__add_child_chunk(chunk, chunk_parent)
12981321
end
12991322

13001323
do
@@ -1361,6 +1384,107 @@ function __default_compmove(src, f, e, t, dst)
13611384
__lua_table_move(src, f, e, t, dst)
13621385
end
13631386

1387+
---@param root evolved.chunk
1388+
function __add_root_chunk(root)
1389+
local root_index = __list_lwr(__root_list, root, function(a, b)
1390+
return a.__fragment < b.__fragment
1391+
end)
1392+
1393+
for sib_root_index = __root_count, root_index, -1 do
1394+
local sib_root = __root_list[sib_root_index]
1395+
__root_set[sib_root.__fragment] = sib_root_index + 1
1396+
__root_list[sib_root_index + 1] = sib_root
1397+
end
1398+
1399+
__root_set[root.__fragment] = root_index
1400+
__root_list[root_index] = root
1401+
__root_count = __root_count + 1
1402+
end
1403+
1404+
---@param root evolved.chunk
1405+
function __remove_root_chunk(root)
1406+
if root.__parent then
1407+
__error_fmt('unexpected root chunk: (%s)',
1408+
__lua_tostring(root))
1409+
return
1410+
end
1411+
1412+
local root_index = __root_set[root.__fragment]
1413+
1414+
if not root_index or __root_list[root_index] ~= root then
1415+
__error_fmt('unexpected root chunk: (%s)',
1416+
__lua_tostring(root))
1417+
return
1418+
end
1419+
1420+
for sib_root_index = root_index, __root_count - 1 do
1421+
local sib_root = __root_list[sib_root_index + 1]
1422+
__root_set[sib_root.__fragment] = sib_root_index
1423+
__root_list[sib_root_index] = sib_root
1424+
end
1425+
1426+
__root_set[root.__fragment] = nil
1427+
__root_list[__root_count] = nil
1428+
__root_count = __root_count - 1
1429+
end
1430+
1431+
---@param child evolved.chunk
1432+
---@param parent evolved.chunk
1433+
function __add_child_chunk(child, parent)
1434+
local child_index = __list_lwr(parent.__child_list, child, function(a, b)
1435+
return a.__fragment < b.__fragment
1436+
end)
1437+
1438+
for sib_child_index = parent.__child_count, child_index, -1 do
1439+
local sib_child = parent.__child_list[sib_child_index]
1440+
parent.__child_set[sib_child] = sib_child_index + 1
1441+
parent.__child_list[sib_child_index + 1] = sib_child
1442+
end
1443+
1444+
parent.__child_set[child] = child_index
1445+
parent.__child_list[child_index] = child
1446+
parent.__child_count = parent.__child_count + 1
1447+
1448+
parent.__with_fragment_edges[child.__fragment] = child
1449+
child.__without_fragment_edges[child.__fragment] = parent
1450+
1451+
child.__parent = parent
1452+
end
1453+
1454+
---@param child evolved.chunk
1455+
function __remove_child_chunk(child)
1456+
local parent = child.__parent
1457+
1458+
if not parent then
1459+
__error_fmt('unexpected child chunk: (%s)',
1460+
__lua_tostring(child))
1461+
return
1462+
end
1463+
1464+
local child_index = parent.__child_set[child]
1465+
1466+
if not child_index or parent.__child_list[child_index] ~= child then
1467+
__error_fmt('unexpected child chunk: (%s)',
1468+
__lua_tostring(child))
1469+
return
1470+
end
1471+
1472+
for sib_child_index = child_index, parent.__child_count - 1 do
1473+
local next_sib_child = parent.__child_list[sib_child_index + 1]
1474+
parent.__child_set[next_sib_child] = sib_child_index
1475+
parent.__child_list[sib_child_index] = next_sib_child
1476+
end
1477+
1478+
parent.__child_set[child] = nil
1479+
parent.__child_list[parent.__child_count] = nil
1480+
parent.__child_count = parent.__child_count - 1
1481+
1482+
parent.__with_fragment_edges[child.__fragment] = nil
1483+
child.__without_fragment_edges[child.__fragment] = nil
1484+
1485+
child.__parent = nil
1486+
end
1487+
13641488
---@param chunk evolved.chunk
13651489
function __update_chunk_caches(chunk)
13661490
local chunk_parent = chunk.__parent
@@ -2945,66 +3069,37 @@ function __purge_chunk(chunk)
29453069
__shrink_chunk(chunk, 0)
29463070
end
29473071

2948-
local chunk_parent = chunk.__parent
2949-
local chunk_fragment = chunk.__fragment
2950-
2951-
local chunk_fragment_list = chunk.__fragment_list
2952-
local chunk_fragment_count = chunk.__fragment_count
2953-
2954-
local with_fragment_edges = chunk.__with_fragment_edges
2955-
local without_fragment_edges = chunk.__without_fragment_edges
2956-
2957-
if not chunk_parent then
2958-
local existing_root_index = __root_set[chunk_fragment]
2959-
local existing_root_chunk = __root_list[existing_root_index]
2960-
2961-
if existing_root_chunk ~= chunk then
2962-
__error_fmt('unexpected root chunk (%s)',
2963-
__lua_tostring(existing_root_chunk))
2964-
end
2965-
2966-
for root_index = existing_root_index, __root_count - 1 do
2967-
local next_root = __root_list[root_index + 1]
2968-
__root_set[next_root.__fragment] = root_index
2969-
__root_list[root_index] = next_root
2970-
end
2971-
2972-
__root_set[chunk_fragment] = nil
2973-
__root_list[__root_count] = nil
2974-
__root_count = __root_count - 1
3072+
if not chunk.__parent then
3073+
__remove_root_chunk(chunk)
3074+
else
3075+
__remove_child_chunk(chunk)
29753076
end
29763077

29773078
do
2978-
local major = chunk_fragment
3079+
local major = chunk.__fragment
29793080
local major_chunks = __major_chunks[major]
29803081

29813082
if major_chunks and __assoc_list_remove(major_chunks, chunk) == 0 then
29823083
__major_chunks[major] = nil
29833084
end
29843085
end
29853086

2986-
for chunk_fragment_index = 1, chunk_fragment_count do
2987-
local minor = chunk_fragment_list[chunk_fragment_index]
3087+
for chunk_fragment_index = 1, chunk.__fragment_count do
3088+
local minor = chunk.__fragment_list[chunk_fragment_index]
29883089
local minor_chunks = __minor_chunks[minor]
29893090

29903091
if minor_chunks and __assoc_list_remove(minor_chunks, chunk) == 0 then
29913092
__minor_chunks[minor] = nil
29923093
end
29933094
end
29943095

2995-
if chunk_parent then
2996-
chunk.__parent, chunk_parent.__child_count = nil, __assoc_list_remove_ex(
2997-
chunk_parent.__child_set, chunk_parent.__child_list, chunk_parent.__child_count,
2998-
chunk)
2999-
end
3000-
3001-
for with_fragment, with_fragment_edge in __lua_next, with_fragment_edges do
3002-
with_fragment_edges[with_fragment] = nil
3096+
for with_fragment, with_fragment_edge in __lua_next, chunk.__with_fragment_edges do
3097+
chunk.__with_fragment_edges[with_fragment] = nil
30033098
with_fragment_edge.__without_fragment_edges[with_fragment] = nil
30043099
end
30053100

3006-
for without_fragment, without_fragment_edge in __lua_next, without_fragment_edges do
3007-
without_fragment_edges[without_fragment] = nil
3101+
for without_fragment, without_fragment_edge in __lua_next, chunk.__without_fragment_edges do
3102+
chunk.__without_fragment_edges[without_fragment] = nil
30083103
without_fragment_edge.__with_fragment_edges[without_fragment] = nil
30093104
end
30103105

0 commit comments

Comments
 (0)