Skip to content

Conversation

adnanhemani
Copy link
Contributor

This PR adds the Events instrumentation for the Iceberg REST Service APIs, surrounding the default delegated call to the business logic APIs.

@adnanhemani adnanhemani marked this pull request as ready for review August 31, 2025 06:42
@@ -777,8 +777,8 @@ public Response sendNotification(
securityContext,
prefix,
catalog -> {
catalog.sendNotification(tableIdentifier, notificationRequest);
return Response.status(Response.Status.NO_CONTENT).build();
boolean notificationSent = catalog.sendNotification(tableIdentifier, notificationRequest);
Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated 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.

No, at the moment we do not get whether the notification was sent successfully or not. So I've introduced this change so that we can surface that information. (There are code paths possible where the notificationSent can be false but the call still returns without error).

But to be fair, I'm not sure what notificationSent really helps with. So please let me know what you think.

Copy link
Contributor

Choose a reason for hiding this comment

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

In this case this requires a modification of the OpenAPI spec. See my related comment:

https://github.com/apache/polaris/pull/2482/files#r2318079257

Copy link
Contributor

Choose a reason for hiding this comment

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

Also: status(Response.Status.NO_CONTENT).entity(notificationSent) is contradictory: the response for a 204 status should not contain any body:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/204

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Needing an OpenAPI spec change and ML thread regarding this is a fair ask. Let me revert this out for now - maybe we can proceed without the result of the sendNotification call first and then in parallel, I can start the ML thread for this.

Once we reach a consensus as a community, then we can go back and resolve the TODO.

@@ -777,8 +777,8 @@ public Response sendNotification(
securityContext,
prefix,
catalog -> {
catalog.sendNotification(tableIdentifier, notificationRequest);
return Response.status(Response.Status.NO_CONTENT).build();
boolean notificationSent = catalog.sendNotification(tableIdentifier, notificationRequest);
Copy link
Contributor

Choose a reason for hiding this comment

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

In this case this requires a modification of the OpenAPI spec. See my related comment:

https://github.com/apache/polaris/pull/2482/files#r2318079257

}

private String getCatalogFromPrefix(String prefix, RealmContext realmContext) {
return prefixParser.prefixToCatalogName(realmContext, prefix);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: inline.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed.

adutra
adutra previously approved these changes Sep 4, 2025
import org.apache.polaris.service.events.AfterAttemptTaskEvent;
import org.apache.polaris.service.events.BeforeAttemptTaskEvent;
import org.apache.polaris.service.events.BeforeLimitRequestRateEvent;
import org.apache.polaris.service.events.IcebergRestCatalogEvents;

public abstract class PolarisPersistenceEventListener extends PolarisEventListener {

// TODO: Ensure all events (except RateLimiter ones) call `addToBuffer`
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the plan to tackle this later?

Copy link
Contributor

Choose a reason for hiding this comment

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

BTW the comment is outdated:

Suggested change
// TODO: Ensure all events (except RateLimiter ones) call `addToBuffer`
// TODO: Ensure all events (except RateLimiter ones) call `processEvent`

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, the plan is to tackle in a separate PR - I would like to keep the focus of this PR on the events itself and the transformations will go in a further PR.

@github-project-automation github-project-automation bot moved this from PRs In Progress to Ready to merge in Basic Kanban Board Sep 4, 2025
Comment on lines 492 to 494
/**
* Table Committed Events are already instrumented at a more granular level than the API itself.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

how and why , are it we tracking it per table ?? this seems like it doesn't follow the pattern
-- BeforEvent
-- do Something
-- After Event

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The TableCommittedEvent was previously merged and there are no changes to it as part of this PR. The idea is that all table commits that happened as part of the same Polaris API call (through the commitTransaction API) will already be tied together through the same request ID and so a new Event for this API is not explicitly required.

Copy link
Contributor

Choose a reason for hiding this comment

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

what is the on before and on after for this, would looks though ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On second thought, you are correct - the Table Committed events are triggered even for non-transactional events. Let me add this.

return delegate.createTable(
prefix, namespace, createTableRequest, accessDelegationMode, realmContext, securityContext);
String catalogName = prefixParser.prefixToCatalogName(realmContext, prefix);
if (!createTableRequest.stageCreate()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

why don't we emit anything for StageCreate ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My understanding is that when a table is stageCreated, then no actual table is made - and therefore there is no new (meta)data created. In that case, I don't think it makes sense to emit a AfterCreateTableEvent if a table was not truly created.

Copy link
Contributor

Choose a reason for hiding this comment

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

But we are not emitting a onBeforeCreateTable too ? never the less what happens when i stage create and then do /commit ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did not realize this - have removed the flag around BeforeCreateTableEvent. Consumers of this event should see this is for a StageCreate table and surface that information accordingly.

return delegate.listViews(
prefix, namespace, pageToken, pageSize, realmContext, securityContext);
String catalogName = prefixParser.prefixToCatalogName(realmContext, prefix);
polarisEventListener.onBeforeListViews(new BeforeListViewsEvent(catalogName, namespace));
Copy link
Contributor

Choose a reason for hiding this comment

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

are the nested namespace encoded by '%1F' in the final even ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a good callout - we should switch this to use Namespace objects instead. Doing in the next revision.

return delegate.createTable(
prefix, namespace, createTableRequest, accessDelegationMode, realmContext, securityContext);
String catalogName = prefixParser.prefixToCatalogName(realmContext, prefix);
if (!createTableRequest.stageCreate()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

But we are not emitting a onBeforeCreateTable too ? never the less what happens when i stage create and then do /commit ?

Comment on lines 492 to 494
/**
* Table Committed Events are already instrumented at a more granular level than the API itself.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

what is the on before and on after for this, would looks though ?

Comment on lines +484 to +485
polarisEventListener.onBeforeRenameView(
new BeforeRenameViewEvent(catalogName, renameTableRequest));
Copy link
Contributor

Choose a reason for hiding this comment

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

no namespace here ? wouldn't it be nice to know namespace before after ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

renameTableRequest has the before and after table identifiers, where an event listener can access that the namespace information.

singhpk234
singhpk234 previously approved these changes Sep 9, 2025
Copy link
Contributor

@singhpk234 singhpk234 left a comment

Choose a reason for hiding this comment

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

The code changes LGTM from IRC POV ! Thanks @adnanhemani

Orthogonal to the PR - I am a bit concerned with seeing the read events being instrumented too, as my understanding was we wanted write API's only (mirroring event's API), this increases load on persistence and the application in general since we use the same JDBC connection pool and we do batching in memory and reads can shoot these up.
My recommendation as part of follow-ups would be :

  • Mark this feature experimental, when ever the E2E machinery is ready
  • run benchmarks with polaris benchmarking tool (whats could be the potential degradation) to identify bottelnecks.

@adnanhemani
Copy link
Contributor Author

Thanks @singhpk234 - makes sense. When we finish the E2E mechanism, we will surely either run the benchmark or mark as experimental.

@singhpk234 singhpk234 merged commit d03c717 into apache:main Sep 17, 2025
14 checks passed
@github-project-automation github-project-automation bot moved this from Ready to merge to Done in Basic Kanban Board Sep 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants