Skip to content

Core, REST: Fix delete file references for DVs in the same Puffin file - #17497

Open
williamhyun wants to merge 4 commits into
apache:mainfrom
williamhyun:multi-DV
Open

Core, REST: Fix delete file references for DVs in the same Puffin file#17497
williamhyun wants to merge 4 commits into
apache:mainfrom
williamhyun:multi-DV

Conversation

@williamhyun

Copy link
Copy Markdown
Member

Motivation: Scan planning responses index delete files by position in the delete-files array.
The index map was keyed on the delete file location alone, but a single Puffin file can hold a deletion vector for each of several data files. Every DV in that file shares a location, so each new DV entry overwrote the previous one and every task referencing a DV in that Puffin file resolved to the same last index.

Changes: Extract DeleteFileSet's private wrapper into a public DeleteFileWrapper, mirroring CharSequenceWrapper, and key the index map on it so serialization uses the same delete file identity that builds the delete-files array.
Fail with a clear message when a task references a delete file that is not in that array.

@williamhyun

Copy link
Copy Markdown
Member Author

cc: @singhpk234

@singhpk234 singhpk234 left a comment

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.

LGTM, thanks @williamhyun !

@singhpk234 singhpk234 changed the title Core: Fix delete file references for DVs in the same Puffin file Core, REST: Fix delete file references for DVs in the same Puffin file Aug 3, 2026

@amogh-jahagirdar amogh-jahagirdar left a comment

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.

Ok thank you @williamhyun I had to think through different solutions (mentioned in the comments) but I came to the conclusion that exposing this is probably the best thing to do. Let's give it another day or so for @nastra to review!

Comment on lines 98 to 99
List<FileScanTask> fileScanTasks,
List<DeleteFile> deleteFiles,

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 was looking at this and in hindsight I think it would've been better to pass in Iterables for both of these. In the end this implementation takes the responsibility of tracking the positions, it's not like we need to rely on the caller to pass in an explicit List.

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.

@amogh-jahagirdar
Could we open this in a follow-up api change?

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.

Yeah that should be good, not needed in this PR

JsonGenerator gen)
throws IOException {
Map<String, Integer> deleteFilePathToIndex = Maps.newHashMap();
Map<DeleteFileWrapper, Integer> deleteFileToIndex = Maps.newHashMap();

@amogh-jahagirdar amogh-jahagirdar Aug 3, 2026

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.

Normally, I think I'd have this map be defined to the interface DeleteFile (and the implementation just uses the DeleteFileWrapper when populating for correctness of the fix) but in this case I think it's actually better to define it to the concrete implementation as it's done here because it makes it clear that this really does need to be the wrapper for proper uniqueness comparison. It guarantees at compile tme that if someone changes the below logic to populate some other type of DeleteFile that we're doing something wrong.

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 would just add a 1 line comment maybe explaining DeleteFileWrapper is important here.

* <p>Delete files are identified by location and content range rather than location alone, as a
* single Puffin file can hold a deletion vector for each of several data files.
*/
public class DeleteFileWrapper implements WrapperSet.Wrapper<DeleteFile> {

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 looked at other approaches (like how difficult it would be to make DeleteFileSet an indexed structure since it does store in insertion order, but removals get complicated etc). So I came to the conclusion that fundamentally we do need to expose DeleteFile equality as is done here via the wrapper.

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.

And I think any other kind of implementation would basically be a O(n) lookup when trying to find the index to serialize (the mapping from delete file to position in the protocol) into the response which feels needlessly suboptimal to just exposing this.

* Wrapper class to adapt DeleteFile for use in maps and sets.
*
* <p>Delete files are identified by location and content range rather than location alone, as a
* single Puffin file can hold a deletion vector for each of several data files.

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.

"single Puffin file can hold multiple DVs"? a DV is already known to be 1:1 for a data file so I don't think we need the "each of several data files"

@williamhyun

Copy link
Copy Markdown
Member Author

Thank you @singhpk234 and @amogh-jahagirdar for the comments!

public String toString() {
return file.location();
}
} No newline at end of file

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.

new line in the end

* <p>Delete files are identified by location and content range rather than location alone, as a
* single Puffin file can hold multiple deletion vectors.
*/
public class DeleteFileWrapper implements WrapperSet.Wrapper<DeleteFile> {

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.

Now that we're exposing this class we should probably have a TestDeleteFileWrapper

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