fix(GODT-3203): Crash in chunkDivide

If for some reason all the message we are trying to sync in a chunk are
deleted from another client it is possible that the input to the build
stage will be empty. This case is now handled correctly.
This commit is contained in:
Leander Beernaert 2024-01-11 08:33:02 +01:00
parent 2895f42a64
commit f565fc4f69
2 changed files with 49 additions and 0 deletions

View File

@ -101,6 +101,23 @@ func (b *BuildStage) run(ctx context.Context) {
continue
}
if len(req.batch) == 0 {
// it is possible that if one does a mass delete on another client an entire download batch fails,
// and we reach this point without any messages to build.
req.onStageCompleted(ctx)
if err := b.output.Produce(ctx, ApplyRequest{
childJob: req.childJob,
messages: nil,
}); err != nil {
err = fmt.Errorf("failed to produce output for next stage: %w", err)
logrus.Errorf(err.Error())
req.job.onError(err)
}
continue
}
err = req.job.messageBuilder.WithKeys(func(_ *crypto.KeyRing, addrKRs map[string]*crypto.KeyRing) error {
chunks := chunkSyncBuilderBatch(req.batch, b.maxBuildMem)

View File

@ -321,3 +321,35 @@ func TestBuildStage_CancelledJobIsDiscarded(t *testing.T) {
_, err := output.Consume(context.Background())
require.ErrorIs(t, err, ErrNoMoreInput)
}
func TestTask_EmptyInputDoesNotCrash(t *testing.T) {
mockCtrl := gomock.NewController(t)
input := NewChannelConsumerProducer[BuildRequest]()
output := NewChannelConsumerProducer[ApplyRequest]()
reporter := mocks.NewMockReporter(mockCtrl)
labels := getTestLabels()
ctx, cancel := context.WithCancel(context.Background())
tj := newTestJob(ctx, mockCtrl, "u", labels)
tj.syncReporter.EXPECT().OnProgress(gomock.Any(), gomock.Eq(int64(10)))
tj.job.begin()
childJob := tj.job.newChildJob("f", 10)
tj.job.end()
stage := NewBuildStage(input, output, 1024, &async.NoopPanicHandler{}, reporter)
go func() {
stage.run(ctx)
}()
require.NoError(t, input.Produce(ctx, BuildRequest{childJob: childJob, batch: []proton.FullMessage{}}))
req, err := output.Consume(ctx)
cancel()
require.NoError(t, err)
require.Len(t, req.messages, 0)
}