Skip to content

[SPARK-31425][SQL][CORE] UnsafeKVExternalSorter/VariableLengthRowBasedKeyValueBatch should also respect UnsafeAlignedOffset#28195

Closed
Ngone51 wants to merge 13 commits intoapache:masterfrom
Ngone51:fix_uao
Closed

[SPARK-31425][SQL][CORE] UnsafeKVExternalSorter/VariableLengthRowBasedKeyValueBatch should also respect UnsafeAlignedOffset#28195
Ngone51 wants to merge 13 commits intoapache:masterfrom
Ngone51:fix_uao

Conversation

@Ngone51
Copy link
Copy Markdown
Member

@Ngone51 Ngone51 commented Apr 12, 2020

What changes were proposed in this pull request?

Make UnsafeKVExternalSorter / VariableLengthRowBasedKeyValueBatch also respect UnsafeAlignedOffset when reading the record and update some out of date comemnts.

Why are the changes needed?

Since BytesToBytesMap respects UnsafeAlignedOffset when writing the record, UnsafeKVExternalSorter should also respect UnsafeAlignedOffset when reading the record from BytesToBytesMap otherwise it will causes data correctness issue.

Unlike UnsafeKVExternalSorter may reading records from BytesToBytesMap, VariableLengthRowBasedKeyValueBatch writes and reads records by itself. Thus, similar to #22053 and comment there, fix for VariableLengthRowBasedKeyValueBatch more likely an improvement for the support of SPARC platform.

Does this PR introduce any user-facing change?

No.

How was this patch tested?

Manually tested HashAggregationQueryWithControlledFallbackSuite with UAO_SIZE=8 to simulate SPARC platform. And tests only pass with this fix.

@SparkQA
Copy link
Copy Markdown

SparkQA commented Apr 12, 2020

Test build #121147 has finished for PR 28195 at commit 6943425.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@Ngone51
Copy link
Copy Markdown
Member Author

Ngone51 commented Apr 13, 2020

ping @cloud-fan @jiangxb1987 @kiszk Please take a look thanks!

// the key address instead of storing the absolute address of the value, the key and value
// must be stored in the same memory page.
// (8 byte key length) (key) (value) (8 byte pointer to next value)
// (uao: klen + vlen + uaolen) (uao: klen) (key) (value) (8 byte pointer to next value)
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.

what does (uao: klen + vlen + uaolen) (uao: klen) mean?

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.

it's (total length) (key length) ...?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yes, if total length here doesn't include the first uaoSize.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How about using the similar description at lines 56-61?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It will be a little bit redundant? Maybe just, (total length) (key length) (key) (value) (8 byte pointer to next value) ?

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.

SGTM

@cloud-fan
Copy link
Copy Markdown
Contributor

can we have a test?

@kiszk
Copy link
Copy Markdown
Member

kiszk commented Apr 13, 2020

@Ngone51
Copy link
Copy Markdown
Member Author

Ngone51 commented Apr 13, 2020

No, I'll check them later and fix together if needed.

@Ngone51
Copy link
Copy Markdown
Member Author

Ngone51 commented Apr 13, 2020

can we have a test?

yet, I updated HashAggregationQueryWithControlledFallbackSuite only to test both 4 and 8 uaoSize, which actually can fail with uaoSize = 8.

Seems better if we could update all those related tests to test both as well.

|once it has processed $fallbackStartsAt input rows).
|The query is ${actual.queryExecution}
|$errorMessage
""".stripMargin
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: indentation issue

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.

Let's fix it

@SparkQA
Copy link
Copy Markdown

SparkQA commented Apr 13, 2020

Test build #121195 has finished for PR 28195 at commit 0b8ebd3.

  • This patch fails Spark unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@Ngone51
Copy link
Copy Markdown
Member Author

Ngone51 commented Apr 14, 2020

I fixed VariableLengthRowBasedKeyValueBatch as well. To be clarify, it won't cause data correctness issue as UnsafeKVExternalSorter does. Unlike UnsafeKVExternalSorter may reading records from BytesToBytesMap, VariableLengthRowBasedKeyValueBatch writes and reads records by itself. Thus, similar to #22053 and your comment there, it's more likely an improvement for the support of SPARC platform.

BTW, I believe we don't need to fix FixedLengthRowBasedKeyValueBatch as it doesn't need to write any length. cc @kiszk

@Ngone51 Ngone51 changed the title [SPARK-31425][SQL][CORE] UnsafeKVExternalSorter should also respect UnsafeAlignedOffset [SPARK-31425][SQL][CORE] UnsafeKVExternalSorter/VariableLengthRowBasedKeyValueBatch should also respect UnsafeAlignedOffset Apr 14, 2020
* probably be using sorting instead of hashing for better cache locality.
*
* The key and values under the hood are stored together, in the following format:
* The key and values under the hood are stored together, in the following format(uaoSize = 4):
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.

in case of uaoSize = 4

long offset = keyRow.getBaseOffset();
int klen = keyRow.getSizeInBytes();
int vlen = Platform.getInt(base, offset - 8) - klen - 4;
int vlen = UnsafeAlignedOffset.getSize(base, offset - uaoSize - uaoSize) - klen - uaoSize;
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.

- uaoSize * 2

totalLength = Platform.getInt(base, offsetInPage) - 4;
currentklen = Platform.getInt(base, offsetInPage + 4);
int uaoSize = UnsafeAlignedOffset.getUaoSize();
int doubleUaoSize = uaoSize + uaoSize;
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.

@SparkQA
Copy link
Copy Markdown

SparkQA commented Apr 14, 2020

Test build #121262 has finished for PR 28195 at commit b1be35e.

  • This patch fails PySpark unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link
Copy Markdown

SparkQA commented Apr 14, 2020

Test build #121276 has finished for PR 28195 at commit bda5823.

  • This patch fails SparkR unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@Ngone51
Copy link
Copy Markdown
Member Author

Ngone51 commented Apr 14, 2020

retest this please.

@kiszk
Copy link
Copy Markdown
Member

kiszk commented Apr 14, 2020

Thank you for updating VariableLengthRowBasedKeyValueBatch and your clarification. Looks good.


fail(newErrorMessage)
case None => // Success
}
Copy link
Copy Markdown
Member

@kiszk kiszk Apr 14, 2020

Choose a reason for hiding this comment

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

I am not confident, but do we need to call setUaoSize(0) at the end of this test? This is because TEST_UAO_SIZE is static.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Oh, yeah. I think we have to reset it.

@SparkQA
Copy link
Copy Markdown

SparkQA commented Apr 14, 2020

Test build #121284 has finished for PR 28195 at commit bda5823.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link
Copy Markdown

SparkQA commented Apr 15, 2020

Test build #121297 has finished for PR 28195 at commit d441e53.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.


public static int getUaoSize() {
return UAO_SIZE;
return TEST_UAO_SIZE == 0 ? UAO_SIZE : TEST_UAO_SIZE;
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.

nit: you can use Utils.isTesting instead

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Other tests might not set UAO size manually, then we'll get 0 in this case.

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.

We should handle the logic of setting/reverting the size in the test code.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

then, we need to figure out all the test cases where used UnsafeAlignedOffset, right?

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.

Why do we need to do that? The default value of TEST_UAO_SIZE should be the same as UAO_SIZE, only if you want to test other values then you need to change it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ok, I get your point. Let me update it later.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

hmm...unfortunately, unsafe project doesn't depend on core. So we can not access the Utils.

*
* The key and values under the hood are stored together, in the following format:
* The key and values under the hood are stored together, in the following format(in case of
* uaoSize = 4):
Copy link
Copy Markdown
Contributor

@jiangxb1987 jiangxb1987 Apr 15, 2020

Choose a reason for hiding this comment

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

why not replace the number below with uaoSize?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I was supposed to do so but it requires more changes in the original content and it is not so clean compares to a concrete number. So I am not sure if we should do. Do you have strong prefer to change in uaoSize way?

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.

The current way doesn't make it clear whether each number 4 represents the uaoSize.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ok. I'll update later.

Object vbase, long voff, int vlen) {
final long recordLength = 8L + klen + vlen + 8;
int uaoSize = UnsafeAlignedOffset.getUaoSize();
int doubleUaoSize = 2 * uaoSize;
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.

doubleUaoSize sounds strange, I'd keep the 2 * uaoSize in the computation...

// Get encoded memory address
// baseObject + baseOffset point to the beginning of the key data in the map, but that
// the KV-pair's length data is stored in the word immediately before that address
// the KV-pair's length data is stored at 2 * uaoSize bytes immediately before that address
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.

sorry I don't get it here why the address is related to uaoSize?

Copy link
Copy Markdown
Member Author

@Ngone51 Ngone51 Apr 15, 2020

Choose a reason for hiding this comment

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

The record format is:

(total length) (key length) (key) (value) (8 byte pointer to next value)
      |             |
   uaoSize       uaoSize

And we now get keyOffset, so we need back walk for 2 usao sizes to get the address of the record.

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.

so you mean we need to add back 2 * uaoSize to cover the space of storing total length and key length? If that's the case then it makes sense.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yes.

@SparkQA
Copy link
Copy Markdown

SparkQA commented Apr 15, 2020

Test build #121324 has finished for PR 28195 at commit 0fb6024.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link
Copy Markdown

SparkQA commented Apr 16, 2020

Test build #121368 has finished for PR 28195 at commit c6f39b5.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@cloud-fan cloud-fan closed this in 40f9dbb Apr 17, 2020
@cloud-fan
Copy link
Copy Markdown
Contributor

thanks, merging to master/3.0!

cloud-fan pushed a commit that referenced this pull request Apr 17, 2020
…dKeyValueBatch should also respect UnsafeAlignedOffset

### What changes were proposed in this pull request?

Make `UnsafeKVExternalSorter` / `VariableLengthRowBasedKeyValueBatch ` also respect `UnsafeAlignedOffset` when reading the record and update some out of date comemnts.

### Why are the changes needed?

Since `BytesToBytesMap` respects `UnsafeAlignedOffset` when writing the record, `UnsafeKVExternalSorter` should also respect `UnsafeAlignedOffset` when reading the record from `BytesToBytesMap` otherwise it will causes data correctness issue.

Unlike `UnsafeKVExternalSorter` may reading records from `BytesToBytesMap`, `VariableLengthRowBasedKeyValueBatch` writes and reads records by itself. Thus, similar to #22053 and [comment](#22053 (comment)) there, fix for `VariableLengthRowBasedKeyValueBatch` more likely an improvement for the support of SPARC platform.

### Does this PR introduce any user-facing change?

No.

### How was this patch tested?

Manually tested `HashAggregationQueryWithControlledFallbackSuite` with `UAO_SIZE=8`  to simulate SPARC platform. And tests only pass with this fix.

Closes #28195 from Ngone51/fix_uao.

Authored-by: yi.wu <yi.wu@databricks.com>
Signed-off-by: Wenchen Fan <wenchen@databricks.com>
(cherry picked from commit 40f9dbb)
Signed-off-by: Wenchen Fan <wenchen@databricks.com>
@Ngone51
Copy link
Copy Markdown
Member Author

Ngone51 commented Apr 17, 2020

thanks all!

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants