Skip to content

fstree: add compressed object decompression tool#4079

Open
End-rey wants to merge 1 commit into
masterfrom
uncompress-util
Open

fstree: add compressed object decompression tool#4079
End-rey wants to merge 1 commit into
masterfrom
uncompress-util

Conversation

@End-rey

@End-rey End-rey commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.93190% with 109 lines in your changes missing coverage. Please review.
✅ Project coverage is 26.66%. Comparing base (6180c09) to head (3c38633).
⚠️ Report is 9 commits behind head on master.

Files with missing lines Patch % Lines
...ject_storage/blobstor/fstree/rewrite_compressed.go 55.55% 30 Missing and 22 partials ⚠️
...torage/blobstor/fstree/rewrite_compressed_linux.go 50.63% 20 Missing and 19 partials ⚠️
cmd/fstree-decompress/root.go 78.31% 10 Missing and 8 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4079      +/-   ##
==========================================
+ Coverage   26.28%   26.66%   +0.38%     
==========================================
  Files         671      674       +3     
  Lines       45862    45860       -2     
==========================================
+ Hits        12056    12230     +174     
+ Misses      32674    32448     -226     
- Partials     1132     1182      +50     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@End-rey End-rey force-pushed the uncompress-util branch from da8c054 to bad672e Compare July 9, 2026 13:38
//
// The method preserves combined physical files by rewriting all hard links to
// the same new combined file. The storage node must not write to this FSTree
// while the migration is running.

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.

Wrong assumption, it will. And the idea is to let it do so.

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.

The migration can now run while the storage node is running on Linux. On other platforms, the node must be stopped because safe concurrent deletion handling is not available.

return RewriteCompressedStats{}, fmt.Errorf("flush pending writes: %w", err)
}

files, err := t.compressedRewriteFiles()

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.

Please don't create these registries. Our mainnet shards have ~16M objects routinely, just listing them is already a problem and it takes a lot of time. You need to do the job while iterating over the tree.

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.

Fixed.

}

func rewriteHardlinkedObjectFile(group []rewriteCompressedFile, data []byte) error {
tmp, err := os.CreateTemp(filepath.Dir(group[0].path), ".rewrite-compressed-*")

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.

Use O_TMPFILE, just like regular FSTree does.

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.

Done.

if err = os.Link(tmpPath, linkPath); err != nil {
return fmt.Errorf("link temporary object file to %q: %w", linkPath, err)
}
if err = os.Rename(linkPath, group[i].path); err != nil {

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.

Be prepared for the node deleting the same file as you walk over the FSTree.

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.

Done.

// The method preserves combined physical files by rewriting all hard links to
// the same new combined file. The storage node must not write to this FSTree
// while the migration is running.
func (t *FSTree) RewriteCompressed() (RewriteCompressedStats, error) {

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.

if it is an FSTree method, why do we need this utility then? it can be a background routing for the next release

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.

Theoretically, yes, I also had this thought, but:

  • either it needs to be synchronized with other activities (deletion first of all to avoid object resurrection) which requires some effort
  • or it keeps the same logic as an outsider, but then having a separate process is easier, can be controlled by shard and can even be performed before the release

Add fstree-decompress for rewriting old zstd-compressed FSTree objects as plain
canonical object bytes. Support single FSTree roots via `--path` and node
configs via `--config`.

Signed-off-by: Andrey Butusov <andrey@nspcc.io>
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