Skip to content
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

Enforce Editor Lock for Write, Append, and Upload Operations in DataNode #2122

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from

Conversation

PrakharJain1509
Copy link

@PrakharJain1509 PrakharJain1509 commented Oct 21, 2024

PR Description

Title: Enforce Editor Lock for Write, Append, and Upload Operations in DataNode

Summary

This PR addresses the issue #2017 where a DataNode could be modified by other editors despite being locked by one. It ensures that once a DataNode is locked with an editor_id, no other editor can perform write, append, or upload operations until the lock is released.

Changes Implemented

  • Modified the write(), append(), and _upload() methods:
    • Enforced locking mechanism to prevent unauthorized modifications by other editors.
    • Raised DataNodeIsBeingEdited exception when a different editor attempts to modify the locked DataNode.
    • Allowed orchestrator writes without editor_id even during an active lock.
  • Updated unit tests in:
    • test_data_node.py to validate the new behavior.
  • Ensured 90% code coverage on all modified methods.

Acceptance Criteria Met

  • Locking mechanism for write, append, and upload is now enforced as expected.
  • Orchestrator writes remain allowed without editor_id.
  • All relevant tests pass with the required code coverage.

This PR ensures consistent locking behavior across all relevant operations in line with the documentation and expected usage.

@PrakharJain1509
Copy link
Author

PrakharJain1509 commented Oct 21, 2024

Hey, @FlorianJacta and @bobbyshermi
I have created this PR addressing all the changes asked, Please review it and let me know if any changes are required.

if self.id not in in_memory_storage:
in_memory_storage[self.id] = []

in_memory_storage[self.id].append(data) # Append new data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the previous data of the data node has no append method.
In other words, what if in_memory_storage[self.id] has no append method?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I added a if instance condition to resolve that. Please review it and let me know if any changes required.

@jrobinAV jrobinAV added Core Related to Taipy Core 🟧 Priority: High Must be addressed as soon Core: Data node labels Oct 22, 2024
@PrakharJain1509
Copy link
Author

@bobbyshermi Did you review it sir?

@PrakharJain1509
Copy link
Author

PrakharJain1509 commented Oct 24, 2024

@bobbyshermi @FlorianJacta @jrobinAV
Please let me know if any changes are required?

@PrakharJain1509
Copy link
Author

@bobbyshermi @jrobinAV @FlorianJacta Please inform me if this issue is open or closed?

@PrakharJain1509
Copy link
Author

@bobbyshermi @jrobinAV @FlorianJacta Please inform me if this issue is open or closed?
@bobbyshermi @jrobinAV @FlorianJacta
???

@jrobinAV jrobinAV added hacktoberfest hacktoberfest issues hacktoberfest - 100💎 Issues rewarded by 100 points labels Oct 31, 2024
@jrobinAV
Copy link
Member

@PrakharJain1509 The issue is still open, yes, and your PR is in the review process. Thank you for your patience. We will get back to you very soon.

@jrobinAV jrobinAV requested review from toan-quach and removed request for bobbyshermi October 31, 2024 07:54
Copy link
Member

@toan-quach toan-quach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution! The changes look good to me, but tests are failing. Please help take a look and fix it 😃

Copy link
Member

@jrobinAV jrobinAV left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a high-quality PR. Thank you very much.

Please have a look at the various comments.

Can you also create a new test file, tests/core/data/test_file_datanode_mixin.py, and test the upload changes you made? The test functions should look like the ones you already created for the write and append functions.

Thx,

@@ -442,9 +444,16 @@ def write(self, data, job_id: Optional[JobId] = None, **kwargs: Dict[str, Any]):
"""
from ._data_manager_factory import _DataManagerFactory

if self.edit_in_progress and editor_id and self.editor_id != editor_id:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, this covers the case where the data node is already locked by a different editor than the one attempting to write it. We also need to check that the self.editor_expiration_date (if it exists) is not past.

@@ -745,3 +745,33 @@ def test_change_data_node_name(self):
# This new syntax will be the only one allowed: https://github.com/Avaiga/taipy-core/issues/806
dn.properties["name"] = "baz"
assert dn.name == "baz"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we are missing a few test cases here:

  • An editor editor_id_1 locked the data node, but the expiration date passed. Another "manual" editor, editor_id_2, should succeed in writing the data node.
  • An editor editor_id_1 locked the data node, but the expiration date passed. Another "manual" editor, editor_id_2, should succeed in appending the data node.
  • The orchestrator locks the data node. A "manual" editor should fail to write the data node.
  • The orchestrator locks the data node. The Orchestrator should succeed in writing the data node.
    The orchestrator locks the data node. A "manual" editor should fail to append it.

raise DataNodeIsBeingEdited(self.id, self.editor_id)

if not editor_id and self.edit_in_progress:
print("Orchestrator writing without editor_id")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This covers the case where the Orchestrator attempts to write a data node locked by an editor. We can eventually add an info log using the _logger attribute, but we don't want any print in the production code. Please remove it.

self._write(data)
self.track_edit(job_id=job_id, **kwargs)
self.unlock_edit()
self.last_edit_date = datetime.now()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last_edit_date setting is already done in the track_edit method called right after. Please revert this line.

Comment on lines +483 to +486

if self._editor_expiration_date and datetime.now() > self._editor_expiration_date:
self.unlock_edit()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see what case we want to cover here. For me, the next condition already covers this case. Can you elaborate? Otherwise, we should revert it.


self.track_edit(timestamp=datetime.now()) # type: ignore[attr-defined]
self._write(data)
self.track_edit(job_id=job_id, editor_id=editor_id, **kwargs) # type: ignore[attr-defined]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.track_edit(job_id=job_id, editor_id=editor_id, **kwargs) # type: ignore[attr-defined]
self.track_edit(timestamp=datetime.now(), editor_id=editor_id, **kwargs) # type: ignore[attr-defined]


self.track_edit(timestamp=datetime.now()) # type: ignore[attr-defined]
self._write(data)
self.track_edit(job_id=job_id, editor_id=editor_id, **kwargs) # type: ignore[attr-defined]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THere is no possible job_id. This cannot be called by the orchestrator.

Comment on lines +124 to +126
if self.edit_in_progress and self.editor_id != editor_id:
raise DataNodeIsBeingEdited(self.id, self.editor_id)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of raising an exception, you should build a specific Reason and add it to the reason_collection, as it is done below in the code for instance. You can re-use the DataNodeEditInProgress reason class.

I would also move this code after the creation of the reason_collection variable:
reason_collection = ReasonCollection()


def _append(self, data):
"""Append data to the existing data in the in-memory storage."""
if self.id not in in_memory_storage:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.id must not be None. you can remove it from the condition.

Comment on lines +106 to +107
if not isinstance(in_memory_storage[self.id], list):
in_memory_storage[self.id] = [in_memory_storage[self.id]]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If in_memory_storage[self.id] is not a list, a NotImplementedError should be raised.

Copy link
Member

@jrobinAV jrobinAV left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments should be resolved first.

@PrakharJain1509
Copy link
Author

Sure, Give me some time, Will do so in some days.

@jrobinAV
Copy link
Member

jrobinAV commented Nov 13, 2024

@PrakharJain1509 FYI, this PR is slightly related to your changes.

#2240

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Core: Data node Core Related to Taipy Core hacktoberfest - 100💎 Issues rewarded by 100 points hacktoberfest hacktoberfest issues 🟧 Priority: High Must be addressed as soon
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants