Skip to content

Commit be4ce9b

Browse files
committed
Test demonstrating race condition in compiler cache when two processes populate it simultaneously.
1 parent e78ec67 commit be4ce9b

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

typed_python/compiler/compiler_cache_test.py

+67
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
import tempfile
16+
import threading
1617
import os
1718
import pytest
1819
from typed_python.test_util import evaluateExprInFreshProcess
@@ -261,6 +262,72 @@ def test_reference_existing_function_twice():
261262
assert len(os.listdir(compilerCacheDir)) == 2
262263

263264

265+
@pytest.mark.skipif('sys.platform=="darwin"')
266+
def test_can_compile_overlapping_code():
267+
common = "\n".join([
268+
"import time",
269+
"import os",
270+
271+
"t0 = time.time()",
272+
"path = os.path.join(os.getenv('TP_COMPILER_CACHE'), 'check.txt')",
273+
"while not os.path.exists(path):",
274+
" time.sleep(.01)",
275+
" assert time.time() - t0 < 2",
276+
])
277+
278+
xmodule1 = "\n".join([
279+
"import common",
280+
"@Entrypoint",
281+
"def f():",
282+
" x = Dict(int, int)()",
283+
" x[3] = 4",
284+
" return x[3]"
285+
])
286+
287+
xmodule2 = "\n".join([
288+
"import common",
289+
"@Entrypoint",
290+
"def g():",
291+
" x = Dict(int, int)()",
292+
" x[3] = 5",
293+
" return x[3]"
294+
])
295+
296+
xmodule3 = "\n".join([
297+
"from x1 import f",
298+
"from x2 import g",
299+
"@Entrypoint",
300+
"def h():",
301+
" return f() + g()"
302+
])
303+
304+
MODULES = {'common.py': common, 'x1.py': xmodule1, 'x2.py': xmodule2, 'x3.py': xmodule3}
305+
306+
with tempfile.TemporaryDirectory() as compilerCacheDir:
307+
# first, compile 'f' and 'g' in two separate processes. Because of the loop
308+
# they will wait until we write out the file that lets them start compiling. Then
309+
# the'll both compile something that has common code.
310+
# we should be able to then use that common code without issue.
311+
threads = [
312+
threading.Thread(
313+
target=evaluateExprInFreshProcess, args=(MODULES, 'x1.f()', compilerCacheDir)
314+
),
315+
threading.Thread(
316+
target=evaluateExprInFreshProcess, args=(MODULES, 'x2.g()', compilerCacheDir)
317+
),
318+
]
319+
for t in threads:
320+
t.start()
321+
322+
with open(os.path.join(compilerCacheDir, "check.txt"), 'w') as f:
323+
f.write('start!')
324+
325+
for t in threads:
326+
t.join()
327+
328+
assert evaluateExprInFreshProcess(MODULES, 'x3.h()', compilerCacheDir) == 9
329+
330+
264331
@pytest.mark.skipif('sys.platform=="darwin"')
265332
def test_compiler_cache_handles_class_destructors_correctly():
266333
xmodule = "\n".join([

0 commit comments

Comments
 (0)