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

Added sync socket result enum for sync socket callback handlers in C API #7015

Merged
merged 20 commits into from
Oct 20, 2023

Conversation

michael-wb
Copy link
Contributor

@michael-wb michael-wb commented Sep 29, 2023

What, How & Why?

Added the realm_sync_socket_callback_result_e enum to be used for passing to the callback handler functions in the C API Platform Networking interface. This contains a subset of the realm_errno_e enum values that can be more easily used with this interface and simplifies this part of the interface, since it narrows down the set of possible errors that should be provided to the callback handlers.

NOTE: Additional errors were included that were believed to be applicable from the Platform Networking point of view, if they can be detected by the implementation. For the most part, the primary values used will be RLM_ERR_SYNC_SOCKET_SUCCESS or RLM_ERR_SYNC_SOCKET_OPERATION_ABORTED.

Fixes #7014

☑️ ToDos

  • 📝 Changelog update
  • 🚦 Tests (or not relevant)
  • C-API, if public C++ API changed.

@michael-wb michael-wb self-assigned this Sep 29, 2023
@cla-bot cla-bot bot added the cla: yes label Sep 29, 2023
@coveralls-official
Copy link

coveralls-official bot commented Sep 29, 2023

Pull Request Test Coverage Report for Build michael.wilkersonbarker_904

  • 111 of 150 (74.0%) changed or added relevant lines in 8 files are covered.
  • 61 unchanged lines in 16 files lost coverage.
  • Overall coverage increased (+0.05%) to 91.614%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/realm/object-store/c_api/types.hpp 8 10 80.0%
test/object-store/c_api/c_api.cpp 52 57 91.23%
src/realm/object-store/c_api/socket_provider.cpp 17 25 68.0%
src/realm/sync/noinst/client_impl_base.cpp 2 10 20.0%
src/realm/sync/network/default_socket.cpp 14 30 46.67%
Files with Coverage Reduction New Missed Lines %
src/realm/index_string.cpp 1 88.09%
test/test_table.cpp 1 99.64%
src/realm/array_string.cpp 2 87.78%
src/realm/cluster.cpp 2 80.25%
src/realm/object-store/c_api/socket_provider.cpp 2 74.48%
src/realm/object-store/shared_realm.cpp 2 93.74%
src/realm/util/serializer.cpp 2 90.91%
test/object-store/c_api/c_api.cpp 2 99.45%
src/realm/sort_descriptor.cpp 3 93.7%
test/test_thread.cpp 3 66.67%
Totals Coverage Status
Change from base Build 1771: 0.05%
Covered Lines: 230731
Relevant Lines: 251852

💛 - Coveralls

Copy link
Contributor

@nhachicha nhachicha left a comment

Choose a reason for hiding this comment

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

LGTM 🎉 minor comments

typedef enum realm_sync_socket_callback_result {
// These error values are pulled directly from realm_errno_e
RLM_ERR_SYNC_SOCKET_SUCCESS = RLM_ERR_NONE,
RLM_ERR_SYNC_SOCKET_OPERATION_ABORTED = RLM_ERR_OPERATION_ABORTED,
Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW we're only using the two above.

static void realm_sync_socket_op_complete(realm_sync_socket_callback* realm_callback, realm_errno_e status,
const char* reason)
static void realm_sync_socket_op_complete(realm_sync_socket_callback* realm_callback,
realm_sync_socket_callback_result_e result, const char* reason)
{
if (realm_callback->get() != nullptr) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we moved the realm_callback release inside this method, is there a scenario where realm_callback->get() == nullptr? In fact, a double invocation (by error) of realm_sync_socket_op_complete will SIGSEGV before invoking get() since the realm_callback pointer was previously released.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We technically don't need it anymore - I'll remove it

@@ -15,8 +15,7 @@ struct CAPITimer : sync::SyncSocketProvider::Timer {
realm_sync_socket_create_timer_func_t create_timer_func,
realm_sync_socket_timer_canceled_func_t cancel_timer_func,
realm_sync_socket_timer_free_func_t free_timer_func)
: m_handler(handler)
Copy link
Collaborator

Choose a reason for hiding this comment

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

what prompted this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We were allowing the CAPITimer to delete the handler, but really it should have been "owned" by the implementation and freed when the complete/cancelled function was called, similar to the post and write_async callbacks.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the idea was that if none of the functions is called and the timer is deallocated, it then deallocates the handler too. Is that still possible?

Copy link
Contributor

@nhachicha nhachicha Oct 4, 2023

Choose a reason for hiding this comment

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

We have to call either realm_sync_socket_timer_canceled or realm_sync_socket_timer_complete which free the handler otherwise the syn client hangs indefinitely waiting for the posted timer(s) to complete https://github.com/realm/realm-core/blob/master/src/realm/sync/client.cpp#L477-L478
This is why we should not rely on the dtor to free it.

Another issue with the current approach is that the m_timer_cancel(m_userdata, m_timer) runs asynchronously whereas realm_release(m_handler); below runs synchronously which will delete the FunctionHandler before it gets a chance to be used inside the event loop

RLM_ERR_SYNC_SOCKET_SUCCESS = RLM_ERR_NONE,
RLM_ERR_SYNC_SOCKET_OPERATION_ABORTED = RLM_ERR_OPERATION_ABORTED,
RLM_ERR_SYNC_SOCKET_RUNTIME = RLM_ERR_RUNTIME,
RLM_ERR_SYNC_SOCKET_OUT_OF_MEMORY = RLM_ERR_OUT_OF_MEMORY,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are we sure we want/need users provide some of these errors? (i.e, RLM_ERR_SYNC_SOCKET_OUT_OF_MEMORY)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, but they could potentially be returned via the async write callback.

};

struct TestWebSocket : realm::c_api::WrapC, WebSocketInterface {
public:
TestWebSocket(DefaultSocketProvider& socket_provider, realm_websocket_endpoint_t endpoint,
TestWebSocket(DefaultSocketProvider* socket_provider, realm_websocket_endpoint_t endpoint,
Copy link
Collaborator

Choose a reason for hiding this comment

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

not sure why we want this change

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks - reverted

Copy link
Collaborator

@danieltabacaru danieltabacaru left a comment

Choose a reason for hiding this comment

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

LGTM - make sure to fix the leak 👍

Copy link
Contributor

@nhachicha nhachicha left a comment

Choose a reason for hiding this comment

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

Tested it again, CI is happy 👍

@michael-wb
Copy link
Contributor Author

michael-wb commented Oct 19, 2023

The three failures in the following test run were due to unrelated timeouts during the test. Created issue 7071 to investigate these failures:
https://evergreen.mongodb.com/version/65315ea632f417d05a36f1c3?redirect_spruce_users=true

@@ -116,7 +107,7 @@ struct CAPIWebSocket : sync::WebSocketInterface {
}

/// Destroys the web socket instance.
~CAPIWebSocket()
virtual ~CAPIWebSocket()
Copy link
Collaborator

Choose a reason for hiding this comment

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

doesn't need to be virtual

src/realm.h Outdated
@@ -355,35 +355,70 @@ typedef struct realm_websocket_endpoint {
bool is_ssl; // true if SSL should be used
} realm_websocket_endpoint_t;

// The following definitions are for internal structures and pointers used
Copy link
Collaborator

Choose a reason for hiding this comment

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

It seems the SDKs use them too. I am not a big fan splitting it this way, but I don't have a strong opinion either. People directly using this API can have their say.

@michael-wb michael-wb merged commit 43853eb into master Oct 20, 2023
2 checks passed
@michael-wb michael-wb deleted the mwb/capi_callback_error_type branch October 20, 2023 19:34
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Consolidate websocket error under realm_web_socket_errno_e
4 participants