-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Retry backend execute on concurrent append #303
base: main
Are you sure you want to change the base?
Changes from all commits
22d9c63
1f4bb5a
1745911
92394ea
1010236
65dca14
bffd2d5
1f0b0a8
44513b3
75050ad
ac3e37c
3a7d5b3
c83f117
4844218
f5e4db0
3f1c004
ae1ee5b
7c0d4f4
c31b679
664796b
4f944ad
79cb07a
b2f2c8c
7f3d72e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,10 @@ | ||
import pytest | ||
from databricks.labs.blueprint.commands import CommandExecutor | ||
from databricks.labs.blueprint.installation import Installation | ||
from databricks.labs.blueprint.parallel import Threads | ||
from databricks.labs.blueprint.wheels import ProductInfo, WheelsV2 | ||
from databricks.sdk.errors import BadRequest | ||
from databricks.sdk.service import compute | ||
|
||
from databricks.labs.lsql import Row | ||
from databricks.labs.lsql.backends import SqlBackend, StatementExecutionBackend | ||
|
@@ -74,7 +77,6 @@ | |
return "PASSED" | ||
""" | ||
|
||
|
||
UNKNOWN_ERROR = """ | ||
from databricks.labs.lsql.backends import RuntimeBackend | ||
from databricks.sdk.errors import Unknown | ||
|
@@ -86,6 +88,37 @@ | |
return "PASSED" | ||
""" | ||
|
||
CONCURRENT_APPEND = ''' | ||
import math | ||
import time | ||
|
||
|
||
def wait_until_seconds_rollover(*, rollover_seconds: int = 10) -> None: | ||
"""Wait until the next rollover. | ||
|
||
Useful to align concurrent writes. | ||
|
||
Args: | ||
rollover_seconds (int) : The multiple of seconds to wait until the next rollover. | ||
""" | ||
nano, micro = 1e9, 1e6 | ||
|
||
nanoseconds_now = time.clock_gettime_ns(time.CLOCK_BOOTTIME) | ||
nanoseconds_target = math.ceil(nanoseconds_now / nano // rollover_seconds) * nano * rollover_seconds | ||
|
||
# To hit the rollover more accurate, first sleep until almost target | ||
nanoseconds_until_almost_target = (nanoseconds_target - nanoseconds_now) - micro | ||
time.sleep(max(nanoseconds_until_almost_target / nano, 0)) | ||
|
||
# Then busy-wait until the rollover occurs | ||
while time.clock_gettime_ns(time.CLOCK_BOOTTIME) < nanoseconds_target: | ||
pass | ||
|
||
|
||
wait_until_seconds_rollover() | ||
spark.sql("UPDATE {table_full_name} SET y = y * 2 WHERE (x % 2 = 0)") | ||
''' | ||
|
||
|
||
@pytest.mark.xfail | ||
def test_runtime_backend_works_maps_permission_denied(ws): | ||
|
@@ -139,6 +172,27 @@ def test_runtime_backend_errors_handled(ws, query): | |
assert result == "PASSED" | ||
|
||
|
||
def test_runtime_backend_handles_concurrent_append(ws, make_random, make_table) -> None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nfx : I copied this from the tests above to integration test the runtime backend. However, it is not really the |
||
commands = CommandExecutor( | ||
ws.clusters, | ||
ws.command_execution, | ||
lambda: ws.config.cluster_id, | ||
language=compute.Language.PYTHON, | ||
) | ||
table = make_table(name=f"lsql_test_{make_random()}", ctas="SELECT r.id AS x, random() AS y FROM range(1000000) r") | ||
|
||
def update_table() -> None: | ||
commands.run(CONCURRENT_APPEND.format(table_full_name=table.full_name)) | ||
|
||
try: | ||
Threads.strict("concurrent appends", [update_table, update_table]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this does not fail due to the lock in the |
||
except BadRequest as e: | ||
if "DELTA_CONCURRENT_APPEND" in str(e): | ||
assert False, str(e) | ||
else: | ||
raise # Raise in case of unexpected error | ||
|
||
|
||
def test_statement_execution_backend_works(ws, env_or_skip): | ||
sql_backend = StatementExecutionBackend(ws, env_or_skip("TEST_DEFAULT_WAREHOUSE_ID")) | ||
rows = list(sql_backend.fetch("SELECT * FROM samples.nyctaxi.trips LIMIT 10")) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Introduced this error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ConcurrentModification
to be precise - we can concurrently delete, append or update