Skip to content

Conversation

quentingodeau
Copy link
Contributor

Hello,

While debugging I saw that the BufferedFileWriter was splitting incoming buffer to smaller one before writing then.

# Test data
curl https://us-prd-motherduck-open-datasets.s3.amazonaws.com/hacker_news/parquet/hacker_news_2021_2022.parquet -o data/hacker_news_2021_2022.parquet

# Tests
for i in seq {1..10}; do rm out.parquet; time ./build/debug/duckdb -c "COPY (SELECT * FROM '../data/hacker_news_2021_2022.parquet' ORDER BY 'id') TO './out.parquet'"; done >with_changes.log 2>&1

Here the result I was expecting better improvement...

Before the change
without_changes.log

After
with_changes.log

But I still propose this PR because depending on the underlying filesystem it may be preferable to have larger buffer.

Flush(); // Flush buffer before writing every things else
}
idx_t remaining_to_write = write_size - to_copy;
fs.Write(*handle, (void *)(buffer + to_copy), remaining_to_write);
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 the only point that is bothering me... Here I have done a C cast style because the input data is a const std::uint8_t type...

Copy link
Contributor

@Tishj Tishj Mar 16, 2024

Choose a reason for hiding this comment

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

That looks fine to me, it's important that the + to_copy is done before the cast and you did just that 👍
However we don't like having c-style casts, use reinterpret_cast instead here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

in this case unfortunately it's a const_cast operation :(
cf 3931b0b

// Perform direct IO, the buffer to write is larger than the internal buffer
// it does not make sens to split a larger buffer into smaller one
idx_t to_copy = 0;
if (offset != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this comment be clarified further?
It sounds like we're not appending to our buffer and flushing it as is, but in reality we're filling our buffer up to FILE_BUFFER_SIZE and then flushing it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

is it better ? 3931b0b

@github-actions github-actions bot marked this pull request as draft March 17, 2024 10:04
@quentingodeau quentingodeau marked this pull request as ready for review March 17, 2024 10:06
Copy link
Contributor

@samansmink samansmink left a comment

Choose a reason for hiding this comment

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

Hey @quentingodeau thanks for the PR! I added one comment, the rest looks good!

@github-actions github-actions bot marked this pull request as draft March 19, 2024 06:12
@quentingodeau quentingodeau marked this pull request as ready for review March 19, 2024 06:16
Copy link
Collaborator

@Mytherin Mytherin left a comment

Choose a reason for hiding this comment

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

Thanks! Looks good - this is a good idea. One comment:

to_copy = FILE_BUFFER_SIZE - offset;
memcpy(data.get() + offset, buffer, to_copy);
offset += to_copy;
Flush(); // Flush buffer before writing every things else
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we call Flush() followed by fs.Write() of the entire incoming buffer below without first copying part of the buffer into the existing buffer? I don't quite see the benefit of first copying part of the buffer into the original file buffer, and it complicates the code here. Two write calls are happening in both cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my opinion the underlying FS expect that the buffered are size at least to the size that has been configured. On a remote FS I think it may impact some performance (depending of course of the implementation), and I wanted to avoid the underlying FS to add an extract layer of buffers.
This is only my opinion and you have the final words regarding this. Please confirm if you want me to do the change or not :)

Copy link
Collaborator

Choose a reason for hiding this comment

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

I can see that - let's keep it as-is then

@Mytherin
Copy link
Collaborator

Thanks!

@Mytherin Mytherin merged commit 2626cb2 into duckdb:main Mar 21, 2024
github-actions bot pushed a commit to duckdb/duckdb-r that referenced this pull request Mar 21, 2024
Merge pull request duckdb/duckdb#11203 from quentingodeau/feature/buffer-writer
krlmlr added a commit to duckdb/duckdb-r that referenced this pull request Mar 23, 2024
Merge pull request duckdb/duckdb#11203 from quentingodeau/feature/buffer-writer
github-actions bot pushed a commit to duckdb/duckdb-r that referenced this pull request Mar 28, 2024
Merge pull request duckdb/duckdb#11203 from quentingodeau/feature/buffer-writer
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.

4 participants