-
Notifications
You must be signed in to change notification settings - Fork 116
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
SNOW-1418523 Make Session thread safe #2312
SNOW-1418523 Make Session thread safe #2312
Conversation
…iables-thread-safe
…iables-thread-safe
…iables-thread-safe
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
…iables-thread-safe
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
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.
For other reviewers: Turning off whitespace comparison simplifies quite a bit.
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
…iables-thread-safe
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
CHANGELOG.md
Outdated
@@ -6,6 +6,8 @@ | |||
|
|||
#### New Features | |||
|
|||
- Updated `Session` class to be thread-safe. This allows concurrent query submission, dataframe operations, UDF and store procedure registration, and concurret file uploads. |
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.
Typo: concurret
CHANGELOG.md
Outdated
@@ -6,6 +6,8 @@ | |||
|
|||
#### New Features | |||
|
|||
- Updated `Session` class to be thread-safe. This allows concurrent query submission, dataframe operations, UDF and store procedure registration, and concurret file uploads. | |||
- One limitation is that updating `Session` configurations inside multiple-threads may cause other active thread to break. Please update `Session` configurations before starting multiple threads. |
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.
This details isn't needed in the changelog. It should be somewhere else in the doc.
@@ -184,6 +185,15 @@ def __init__( | |||
"_skip_upload_on_content_match" in signature.parameters | |||
) | |||
|
|||
@property | |||
def _cursor(self) -> SnowflakeCursor: | |||
if not hasattr(self._thread_store, "cursor"): |
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.
is hasattr()
itself thread-safe?
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.
yes, hasattr
is read-only operation on thread local object.
@@ -38,6 +39,7 @@ class TelemetryField(Enum): | |||
TYPE_PERFORMANCE_DATA = "snowpark_performance_data" | |||
TYPE_FUNCTION_USAGE = "snowpark_function_usage" | |||
TYPE_SESSION_CREATED = "snowpark_session_created" | |||
TYPE_CURSOR_CREATED = "snowpark_cursor_created" |
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.
Is the purpose to know whether multiple cursor is used?
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.
Yes, this addition is part of collecting telemtry. It will track if a cursor is used in a new thread.
runtime_version = ( | ||
f"{sys.version_info[0]}.{sys.version_info[1]}" | ||
if not runtime_version | ||
else runtime_version | ||
) |
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.
Nit: no need to change. Just for your reference:
runtime_version = runtime_version or f"{sys.version_info[0]}.{sys.version_info[1]}"
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.
yep. that's much simpler. I'll update the code.
) | ||
with self._package_lock: | ||
result_dict = ( | ||
existing_packages_dict if existing_packages_dict is not None else {} |
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.
why the .copy() is removed here?
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.
The original version of this code had this pattern.
result_dict = existing_packages_dict if existing_pacakges_dict else {}
...
for package in dependency_packages:
name = package.name
if name in result_dict:
...
else:
result["name"] = name
I refactored it the wrong way using this pattern
result_dict = existing_packages_dict.copy() if existing_pacakges_dict else {}
...
for package in dependency_packages:
name = package.name
if name in result_dict:
...
else:
result["name"] = name
if existing_packages_dict:
existing_pacakges_dict.update(result_dict)
I noticed this refactor is not correct as the update step can overwrite updates from a different thread.
So in this change, I undid the refactor and updated the code as follows:
with self._package_lock:
result_dict = existing_packages_dict if existing_pacakges_dict else {}
...
for package in dependency_packages:
name = package.name
if name in result_dict:
...
else:
result["name"] = name
SP Precommit run with this change: https://ci-dev-142.int.snowflakecomputing.com/job/PythonStoredProcBuildPrecommitTest/1395/ |
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
Seems like your changes contain some Local Testing changes, please request review from @snowflakedb/local-testing |
Which Jira issue is this PR addressing? Make sure that there is an accompanying issue to your PR.
Fixes SNOW-1418523
Fill out the following pre-review checklist:
Please describe how your code solves the related issue.
This PR is merging back add updates from feature branch to main branch. It includes the following changes: