Skip to content

feat: implement STCS compaction#430

Open
dkharms wants to merge 5 commits into
336-merge-sourcefrom
336-compaction
Open

feat: implement STCS compaction#430
dkharms wants to merge 5 commits into
336-merge-sourcefrom
336-compaction

Conversation

@dkharms

@dkharms dkharms commented May 27, 2026

Copy link
Copy Markdown
Member

Description

Adds a STCS (Size-Tiered Compaction Strategy) planner that groups sealed fractions into time-bins and selects compaction candidates, and an executor that merges them into a new sealed fraction via k-way merge.


  • I have read and followed all requirements in CONTRIBUTING.md;
  • I used LLM/AI assistance to make this pull request;

If you have used LLM/AI assistance please provide model name and full prompt:

Model: {{model-name}}
Prompt: {{prompt}}

@dkharms dkharms changed the title feat: implement compaction feat: implement STCS compaction May 27, 2026
@dkharms dkharms marked this pull request as ready for review May 29, 2026 09:57
@eguguchkin eguguchkin requested review from eguguchkin and forshev June 1, 2026 11:29
@eguguchkin eguguchkin added this to the v0.73.0 milestone Jun 2, 2026
Comment thread storeapi/store.go Outdated
fracManagerStop func()

SkipMaskManager *skipmaskmanager.SkipMaskManager
Executor *compaction.Executor

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: maybe rename Executor field to something associated with compaction? like CompactionExecutor or Compactor

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.

Yep, done.

Comment thread compaction/executor.go Outdated
zap.Strings("names", names),
)

preloaded, err := Merge(t.filename, common.SealParams{}, srcs...)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: should seal params be empty here?

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.

Nope, fixed.

Comment thread compaction/planner.go Outdated

"go.uber.org/zap"

"github.com/alecthomas/units"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

import in the wrong group

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.

Fixed.

Comment thread fracmanager/fraction_provider.go Outdated
Comment thread indexwriter/index.go Outdated
Comment thread config/config.go
}
}

func (fm *FracManager) FractionName() string {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: maybe we should move the implementation to fractionProvider to avoid duplication in fractionProvider.CreateActive

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.

Done.

Comment thread compaction/planner.go Outdated
func NewPlanner(ctx context.Context, fm *fracmanager.FracManager, cfg Config) *planner {
p := planner{
cfg: cfg,
ctx: ctx,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: a small simplification here (and I think this would be more canonical) — we need to create a child context with cancellation

ctx, cancel := context.WithCancel(ctx)

and instead of storing done, store cancel and call it in Stop.

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.

Done.

Comment thread compaction/planner.go Outdated
return ordered
}

func names[T interface{ Info() *common.Info }, S ~[]T](fracs S) []string {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: since we declared the fraction interface, maybe we should use it here too?

func names[T fraction, S ~[]T](fracs S) []string {

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.

Done.

Comment thread compaction/planner.go

select {
case p.tasks <- task:
case <-time.NewTimer(time.Second).C:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We don't release claimed factions here

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.

Done.

Comment thread compaction/stcs.go Outdated
continue
}

buckets = append(buckets, bucket{uint64(avg), current})

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's explicitly specify fields everywhere. Not all IDEs can handle implicit field initialization, and there's a risk of breaking initialization during refactoring.

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.

Done.

Comment thread compaction/planner.go Outdated
return fnames
}

func powerOfTwo(v uint64) uint64 {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: this name confused me at first. I suggest ceilPowerOfTwo

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.

Done.

Comment thread compaction/planner.go

onComplete: func(s *sealed.PreloadedData, err error) {
if err != nil {
compactionResultTotal.WithLabelValues(bucketSize, "error").Inc()

@eguguchkin eguguchkin Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

And here we don't release claimed factions

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.

Done.

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.

3 participants