Skip to content

Fixed ClassCastException during Multi-Stage Queries on real-time segments - #16607

Closed
nozjkoitop wants to merge 15 commits into
apache:masterfrom
deep-bi:feature-fix-msq-with-hllsketch-in-realtime
Closed

nozjkoitop wants to merge 15 commits into
apache:masterfrom
deep-bi:feature-fix-msq-with-hllsketch-in-realtime

Conversation

@nozjkoitop

@nozjkoitop nozjkoitop commented Jun 14, 2024 •

Copy link
Copy Markdown
Contributor

Fixed issue when msq queries throw ClassCastException with "includeSegmentSource": "REALTIME" and supervisor running.

Caused by: java.lang.ClassCastException: class [B cannot be cast to class org.apache.druid.query.aggregation.datasketches.hll.HllSketchHolder ([B is in module java.base of loader 'bootstrap'; org.apache.druid.query.aggregation.datasketches.hll.HllSketchHolder is in unnamed module of loader java.net.URLClassLoader @38792286)
	at org.apache.druid.query.aggregation.datasketches.hll.HllSketchHolderObjectStrategy.toBytes(HllSketchHolderObjectStrategy.java:31)
	at org.apache.druid.segment.serde.ComplexMetricSerde.toBytes(ComplexMetricSerde.java:119)
	at org.apache.druid.frame.field.ComplexFieldWriter.writeTo(ComplexFieldWriter.java:65)
	at org.apache.druid.frame.write.RowBasedFrameWriter.writeDataUsingFieldWriters(RowBasedFrameWriter.java:291)
	at org.apache.druid.frame.write.RowBasedFrameWriter.writeData(RowBasedFrameWriter.java:246)
	at org.apache.druid.frame.write.RowBasedFrameWriter.addSelection(RowBasedFrameWriter.java:122)
	at org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.populateFrameWriterAndFlushIfNeeded(ScanQueryFrameProcessor.java:348)
	at org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.populateFrameWriterAndFlushIfNeededWithExceptionHandling(ScanQueryFrameProcessor.java:329)
	at org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.runWithLoadedSegment(ScanQueryFrameProcessor.java:231)
	at org.apache.druid.msq.querykit.BaseLeafFrameProcessor.runIncrementally(BaseLeafFrameProcessor.java:87)
	at org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.runIncrementally(ScanQueryFrameProcessor.java:158)
	at org.apache.druid.frame.processor.FrameProcessors$1FrameProcessorWithBaggage.runIncrementally(FrameProcessors.java:75)
	at org.apache.druid.frame.processor.FrameProcessorExecutor$1ExecutorRunnable.runProcessorNow(FrameProcessorExecutor.java:230)
	... 8 more

After some investigation was found that selector's getObject() for real-time segments was returning a byte array representation of HllSketch but still was trying to convert it to a byte[]. While HllSketchHolderObjectStrategy expects to have HllSketchHolder instance in toBytes() leading to the ClassCastException.

This PR has:

  • been self-reviewed.
  • added documentation for new or modified features or behaviors.
  • a release note entry in the PR description.
  • added Javadocs for most classes and all non-trivial methods. Linked related entities via Javadoc links.
  • added or updated version, license, or notice information in licenses.yaml
  • added comments explaining the "why" and the intent of the code wherever would not be obvious for an unfamiliar reader.
  • added unit tests or modified existing tests to cover new code paths, ensuring the threshold for code coverage is met.
  • added integration tests.
  • been tested in a test Druid cluster.

…hat include columns of HLLSketch type resulted in a ClassCastException.
Comment on lines +118 to +122
if (val == null) {
return ByteArrays.EMPTY_ARRAY;
} else if (val instanceof byte[]) {
return (byte[]) val;
} else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this is incorrect because there might exist a serde where the deserialized value is byte[], however, the serialized value can be something else.

For example, different compression techniques can transform a deserialized byte[] array to a different serialized byte[] array. This would be unique to the complex type, so it shouldn't be a universal change. Instead, the following changes can be made:

  1. If this only occurs in the HllSketchBuild serde, you can make this change specific to the HllSketchBuild serde.
  2. Else, if this occurs with all the complex types while running MSQ tasks on complex metrics, you can make the changes in MSQ-specific classes (after confirming where the byte[] array is coming from).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing that out! It looks like this issue might not be limited to just the HLLSketch. None of the ObjectStrategies seem to fit this scenario, as they all expect specific objects for the toBytes() method. Using it with a byte array directly would lead to the CCE. I'll look into why selector.getObject is returning a byte array for a real-time segment maybe it could be fixed there as well. It is not appears in MSQ classes directly tho, it shows up at ComplexFieldWriter.writeTo()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

np! Since the issue is bubbling up from the column value selectors, you can check who creates those, and why they are returning a byte array instead of the desired object type.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I made some research and it looks like it's normal for selector.getObject to return a byte[] for real-time segments. This happens because it uses RowBasedColumnValueSelector instead of ObjectColumnSelector. It doesn't go through GenericIndexed.copyBufferAndGet() and strategy.fromByteBuffer(), and just grabs the byte[] directly from the ByteBuffer using rowSupplier.get() (at least in case of ComplexType from RealTime segment MSQ).

Right now, we don't have an ObjectStrategy that needs a byte[] as input, so initial setup would likely cause CCE failures. But you're right, we might need to handle this in the future. So, I've moved this check to the ObjectStrategy as a defaul void, making it easy to override if needed.

{
if (val != null) {
byte[] bytes = getObjectStrategy().toBytes(val);
byte[] bytes = getObjectStrategy().objectToBytes(val);

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation

Invoking [ComplexMetricSerde.getObjectStrategy](1) should be avoided because it has been deprecated.
@nozjkoitop
nozjkoitop requested a review from LakshSingla June 24, 2024 06:52
@LakshSingla

Copy link
Copy Markdown
Contributor

Thanks for the changes @nozjkoitop. I'll review them shortly.

@nozjkoitop

Copy link
Copy Markdown
Contributor Author

Thanks for the changes @nozjkoitop. I'll review them shortly.

@LakshSingla Could I remind you to have a look on that please?

@LakshSingla

Copy link
Copy Markdown
Contributor

Sorry for the delay @nozjkoitop and thanks for the update 🚀
Can you please add a test in the MSQSelectTest or MSQInsertTest to validate that the PR fails before with the exception you are seeing and passes after this patch? This should be easy to reproduce. LMK if you need help with that.

The new approach is a lot cleaner than the previous one, but I still wanna see if there's a way to restrict the change to MSQ, since I suspect that there's a faulty selector at play. The MSQ test case would help in debugging this as well.

@github-actions github-actions Bot added Area - Batch Ingestion Area - MSQ For multi stage queries - https://github.com/apache/druid/issues/12262 labels Jul 12, 2024
@nozjkoitop

Copy link
Copy Markdown
Contributor Author

Can you please add a test in the MSQSelectTest or MSQInsertTest to validate that the PR fails before with the exception you are seeing and passes after this patch? This should be easy to reproduce.

I've added new test-case with hyperUnique column in select from realtime segment, please have a look

@nozjkoitop

Copy link
Copy Markdown
Contributor Author

@LakshSingla WDYT?

@LakshSingla

Copy link
Copy Markdown
Contributor

Hey @nozjkoitop apologies for the delay. Let me take a look at the patch and get back to you in a couple of days. It seems correct for the most part. I just need to think if there's a less invasive way to do this given that the regression is in MSQ. I wasn't able to get to it due to a few other patches I was working on, but I'll prioritize this change. Thanks a lot for being patient with me!

@nozjkoitop

Copy link
Copy Markdown
Contributor Author

Hey @LakshSingla, just a kindly reminder about this PR :)

@adarshsanjeev

Copy link
Copy Markdown
Contributor

@nozjkoitop I think @LakshSingla's comment was to only make changes that affect MSQ, since the bug is seen only there. I think your changes might affect other queries as well.

@nozjkoitop

nozjkoitop commented Sep 27, 2024 •

Copy link
Copy Markdown
Contributor Author

@nozjkoitop I think @LakshSingla's comment was to only make changes that affect MSQ, since the bug is seen only there. I think your changes might affect other queries as well.

Hi @adarshsanjeev ! The main issue is in ComplexFieldWriter, and it's caused by the ValueSelector potentially returning a byte[], which the writer doesn't expect. This needs to be handled, and could be addressed it in either the writeTo() method or serde.toBytes(). Both of these classes are part of Druid's processing, and honestly, I don’t see any other places that would be more isolated for handling this.

@github-actions

Copy link
Copy Markdown

This pull request has been marked as stale due to 60 days of inactivity.
It will be closed in 4 weeks if no further activity occurs. If you think
that's incorrect or this pull request should instead be reviewed, please simply
write any comment. Even if closed, you can still revive the PR at any time or
discuss it on the dev@druid.apache.org list.
Thank you for your contributions.

@github-actions github-actions Bot added the stale label Nov 27, 2024
…ith-hllsketch-in-realtime

# Conflicts:
#	extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/test/MSQTestBase.java
@nozjkoitop

Copy link
Copy Markdown
Contributor Author

Hi @LakshSingla I've checked the latest druid and described issue is still there, although now there is a NPE on the ui, but provided patch still resolves an issue, so I merged the changes from master. Please take a look.

@github-actions github-actions Bot removed the stale label Dec 19, 2024
@github-actions

Copy link
Copy Markdown

This pull request has been marked as stale due to 60 days of inactivity.
It will be closed in 4 weeks if no further activity occurs. If you think
that's incorrect or this pull request should instead be reviewed, please simply
write any comment. Even if closed, you can still revive the PR at any time or
discuss it on the dev@druid.apache.org list.
Thank you for your contributions.

@nozjkoitop

nozjkoitop commented Mar 5, 2025 •

Copy link
Copy Markdown
Contributor Author

Issue is still there in v32, merged master to solve conflicts

@github-actions github-actions Bot removed the stale label Mar 6, 2025
@github-actions

github-actions Bot commented May 5, 2025

Copy link
Copy Markdown

This pull request has been marked as stale due to 60 days of inactivity.
It will be closed in 4 weeks if no further activity occurs. If you think
that's incorrect or this pull request should instead be reviewed, please simply
write any comment. Even if closed, you can still revive the PR at any time or
discuss it on the dev@druid.apache.org list.
Thank you for your contributions.

@github-actions github-actions Bot added the stale label May 5, 2025
vivek807 added a commit to deep-bi/druid that referenced this pull request May 6, 2025
@github-actions

github-actions Bot commented Jun 2, 2025

Copy link
Copy Markdown

This pull request/issue has been closed due to lack of activity. If you think that
is incorrect, or the pull request requires review, you can revive the PR at any time.

@github-actions github-actions Bot closed this Jun 2, 2025
@gianm

gianm commented Jun 3, 2025

Copy link
Copy Markdown
Contributor

Something seems off with the rebase on master, there's a bunch of extra files. That being said, it seems to me like this error points at a situation where some aspect of the design is sketchy. I will reopen it. @adarshsanjeev has been looking recently into realtime queries in MSQ- would you mind taking a look at this bug?

@gianm gianm reopened this Jun 3, 2025
@github-actions github-actions Bot removed the stale label Jun 4, 2025
@adarshsanjeev

Copy link
Copy Markdown
Contributor

Sure, I can take a look at this bug

@nozjkoitop

Copy link
Copy Markdown
Contributor Author

@adarshsanjeev i see that i messed up the merging before, now ive reset the branch to here and merged it properly. Shall i push that?

@nozjkoitop
nozjkoitop force-pushed the feature-fix-msq-with-hllsketch-in-realtime branch from 6ca88c6 to 7ffe8b5 Compare June 10, 2025 11:09
@github-actions

Copy link
Copy Markdown

This pull request has been marked as stale due to 60 days of inactivity.
It will be closed in 4 weeks if no further activity occurs. If you think
that's incorrect or this pull request should instead be reviewed, please simply
write any comment. Even if closed, you can still revive the PR at any time or
discuss it on the dev@druid.apache.org list.
Thank you for your contributions.

@github-actions github-actions Bot added the stale label Aug 11, 2025
@github-actions

github-actions Bot commented Sep 9, 2025

Copy link
Copy Markdown

This pull request/issue has been closed due to lack of activity. If you think that
is incorrect, or the pull request requires review, you can revive the PR at any time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants