fix(GODT-2424): Sync Builder Message Split

Incorrect math was causing some messages to not be built and be missing
from Gluon.
This commit is contained in:
Leander Beernaert
2023-03-01 09:51:53 +01:00
parent 825031e052
commit 91ab77dce9
2 changed files with 68 additions and 35 deletions

View File

@ -503,41 +503,7 @@ func syncMessages(
return return
} }
var expectedMemUsage uint64 chunks := chunkSyncBuilderBatch(buildBatch.batch, syncMaxMessageBuildingMem)
var chunks [][]proton.FullMessage
{
var lastIndex int
var index int
for _, v := range buildBatch.batch {
var dataSize uint64
for _, a := range v.Attachments {
dataSize += uint64(a.Size)
}
// 2x increase for attachment due to extra memory needed for decrypting and writing
// in memory buffer.
dataSize *= 2
dataSize += uint64(len(v.Body))
nextMemSize := expectedMemUsage + dataSize
if nextMemSize >= syncMaxMessageBuildingMem {
chunks = append(chunks, buildBatch.batch[lastIndex:index])
lastIndex = index
expectedMemUsage = dataSize
} else {
expectedMemUsage = nextMemSize
}
index++
}
if index < len(buildBatch.batch) {
chunks = append(chunks, buildBatch.batch[index:])
} else if index == len(buildBatch.batch) && len(chunks) == 0 {
chunks = [][]proton.FullMessage{buildBatch.batch}
}
}
for index, chunk := range chunks { for index, chunk := range chunks {
logrus.Debugf("Build request: %v of %v count=%v", index, len(chunks), len(chunk)) logrus.Debugf("Build request: %v of %v count=%v", index, len(chunks), len(chunk))
@ -852,3 +818,39 @@ func (a *attachmentDownloader) getAttachments(ctx context.Context, attachments [
func (a *attachmentDownloader) close() { func (a *attachmentDownloader) close() {
a.cancel() a.cancel()
} }
func chunkSyncBuilderBatch(batch []proton.FullMessage, maxMemory uint64) [][]proton.FullMessage {
var expectedMemUsage uint64
var chunks [][]proton.FullMessage
var lastIndex int
var index int
for _, v := range batch {
var dataSize uint64
for _, a := range v.Attachments {
dataSize += uint64(a.Size)
}
// 2x increase for attachment due to extra memory needed for decrypting and writing
// in memory buffer.
dataSize *= 2
dataSize += uint64(len(v.Body))
nextMemSize := expectedMemUsage + dataSize
if nextMemSize >= maxMemory {
chunks = append(chunks, batch[lastIndex:index])
lastIndex = index
expectedMemUsage = dataSize
} else {
expectedMemUsage = nextMemSize
}
index++
}
if lastIndex < len(batch) {
chunks = append(chunks, batch[lastIndex:])
}
return chunks
}

View File

@ -24,6 +24,8 @@ import (
"github.com/ProtonMail/gluon/imap" "github.com/ProtonMail/gluon/imap"
"github.com/ProtonMail/gluon/rfc822" "github.com/ProtonMail/gluon/rfc822"
"github.com/ProtonMail/go-proton-api"
"github.com/bradenaw/juniper/xslices"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -47,3 +49,32 @@ func TestNewFailedMessageLiteral(t *testing.T) {
require.Equal(t, `("text" "plain" () NIL NIL "base64" 114 2)`, parsed.Body) require.Equal(t, `("text" "plain" () NIL NIL "base64" 114 2)`, parsed.Body)
require.Equal(t, `("text" "plain" () NIL NIL "base64" 114 2 NIL NIL NIL NIL)`, parsed.Structure) require.Equal(t, `("text" "plain" () NIL NIL "base64" 114 2 NIL NIL NIL NIL)`, parsed.Structure)
} }
func TestSyncChunkSyncBuilderBatch(t *testing.T) {
// GODT-2424 - Some messages were not fully built due to a bug in the chunking if the total memory used by the
// message would be higher than the maximum we allowed.
const totalMessageCount = 100
msg := proton.FullMessage{
Message: proton.Message{
Attachments: []proton.Attachment{
{
Size: int64(8 * Megabyte),
},
},
},
AttData: nil,
}
messages := xslices.Repeat(msg, totalMessageCount)
chunks := chunkSyncBuilderBatch(messages, 16*Megabyte)
var totalMessagesInChunks int
for _, v := range chunks {
totalMessagesInChunks += len(v)
}
require.Equal(t, totalMessagesInChunks, totalMessageCount)
}