Skip to content

Commit

Permalink
feat(GODT-1917): Sync benchmark
Browse files Browse the repository at this point in the history
Add a benchmark which checks the sync time for a new user with existing
messages.

The code has also been refactored to allow the use of different
connector implementation types. New connectors should be registered with
`utils.RegisterConnector()` before benchmark execution.

Existing IMAP benchmarks can now also run against different connector
implementations.

`ClearUpdates()` was added to the Dummy connector in order to clear the
update queue when benchmarking sync operations.
  • Loading branch information
LBeernaertProton committed Aug 5, 2022
1 parent 29af240 commit b613808
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 34 deletions.
3 changes: 3 additions & 0 deletions benchmarks/gluon_bench/flags/general.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ var (
JsonReporter = flag.String("json-reporter", "", "If specified, will generate a json report with the given filename.")
BenchmarkRuns = flag.Uint("bench-runs", 1, "Number of runs per benchmark.")
ReuseState = flag.Bool("reuse-state", false, "When present, benchmarks will re-use previous run state, rather than a clean slate.")
Connector = flag.String("connector", "dummy", "Key of the connector implementation registered with ConnectorFactory.")
UserName = flag.String("user-name", "user", "Username for the connector user, defaults to 'user'.")
UserPassword = flag.String("user-pwd", "password", "Password for the connector user, defaults to 'password'.")
)
167 changes: 167 additions & 0 deletions benchmarks/gluon_bench/gluon_benchmarks/sync.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package gluon_benchmarks

import (
"context"
"crypto/sha256"
"encoding/hex"
"flag"
"fmt"
"math/rand"
"path/filepath"
"time"

"entgo.io/ent/dialect"
"github.com/ProtonMail/gluon"
"github.com/ProtonMail/gluon/benchmarks/gluon_bench/benchmark"
"github.com/ProtonMail/gluon/benchmarks/gluon_bench/flags"
"github.com/ProtonMail/gluon/benchmarks/gluon_bench/reporter"
"github.com/ProtonMail/gluon/benchmarks/gluon_bench/utils"
"github.com/ProtonMail/gluon/imap"
"github.com/ProtonMail/gluon/profiling"
"github.com/ProtonMail/gluon/store"
"github.com/google/uuid"
_ "github.com/mattn/go-sqlite3"
"github.com/sirupsen/logrus"
)

var (
syncMessageCountFlag = flag.Uint("sync-msg-count", 1000, "Number of messages to sync.")
syncMBoxCountFlag = flag.Uint("sync-mbox-count", 1, "Number of mailboxes to sync.")
)

type Sync struct {
connector utils.ConnectorImpl
server *gluon.Server
mailboxes []string
}

func NewSync() benchmark.Benchmark {
return &Sync{}
}

func (s *Sync) Name() string {
return "sync"
}

func (s *Sync) Setup(ctx context.Context, benchmarkDir string) error {
loggerIn := logrus.StandardLogger().WriterLevel(logrus.TraceLevel)
loggerOut := logrus.StandardLogger().WriterLevel(logrus.TraceLevel)

opts := []gluon.Option{gluon.WithLogger(loggerIn, loggerOut)}

server, err := gluon.New(benchmarkDir, opts...)

if err != nil {
return err
}

s.server = server

connector, err := s.setupConnector(ctx, benchmarkDir)
if err != nil {
return err
}

s.connector = connector

return nil
}

func (s *Sync) setupConnector(ctx context.Context, benchmarkPath string) (utils.ConnectorImpl, error) {
c, err := utils.NewConnector(*flags.Connector)
if err != nil {
return nil, err
}

hash := sha256.Sum256([]byte(*flags.UserName))
id := hex.EncodeToString(hash[:])

storePath := filepath.Join(benchmarkPath, id+".store")
dbPath := filepath.Join(benchmarkPath, id+".db")

if *flags.Verbose {
fmt.Printf("Adding user ID=%v\n BenchPath:'%v'\n DBPath:'%v'\n", id, storePath, dbPath)
}

store, err := store.NewOnDiskStore(storePath, []byte(*flags.UserPassword))
if err != nil {
return nil, err
}

mboxIDs := make([]string, 0, *syncMBoxCountFlag)

for i := uint(0); i < *syncMBoxCountFlag; i++ {
mbox, err := c.Connector().CreateLabel(ctx, []string{uuid.NewString()})
if err != nil {
return nil, err
}

mboxIDs = append(mboxIDs, mbox.ID)
}

messages := [][]byte{
[]byte(utils.MessageEmbedded),
[]byte(utils.MessageMultiPartMixed),
[]byte(utils.MessageAfterNoonMeeting),
}

flagSet := imap.NewFlagSet("\\Recent")

s.mailboxes = make([]string, 0, len(mboxIDs))

for _, mboxID := range mboxIDs {
for i := uint(0); i < *syncMessageCountFlag; i++ {
if _, err := c.Connector().CreateMessage(ctx, mboxID, messages[rand.Intn(len(messages))], flagSet, time.Now()); err != nil {
return nil, err
}
}

s.mailboxes = append(s.mailboxes, mboxID)
}

_, err = s.server.AddUser(
ctx,
c.Connector(),
store,
dialect.SQLite,
fmt.Sprintf("file:%v?cache=shared&_fk=1", dbPath))
if err != nil {
return nil, err
}

return c, nil
}

func (s *Sync) Run(ctx context.Context) (*reporter.BenchmarkRun, error) {
timer := utils.ScopedTimer{}

timer.Start()

err := s.connector.Sync(ctx)

timer.Stop()

if err != nil {
return nil, err
}

var cmdTimings [profiling.CmdTypeTotal][]time.Duration

return reporter.NewBenchmarkRun(timer.Elapsed(), cmdTimings), nil
}

func (s *Sync) TearDown(ctx context.Context) error {
for _, id := range s.mailboxes {
if err := s.connector.Connector().DeleteLabel(ctx, id); err != nil {
return err
}
}

if s.server != nil {
if err := s.server.Close(ctx); err != nil {
return err
}
}

return nil
}
3 changes: 1 addition & 2 deletions benchmarks/gluon_bench/imap_benchmarks/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"time"

"github.com/ProtonMail/gluon/benchmarks/gluon_bench/flags"
"github.com/ProtonMail/gluon/benchmarks/gluon_bench/utils"
"github.com/bradenaw/juniper/xslices"
"github.com/emersion/go-imap"
"github.com/emersion/go-imap/client"
Expand All @@ -23,7 +22,7 @@ func NewClient(addr string) (*client.Client, error) {
return nil, err
}

if err := client.Login(utils.UserName, utils.UserPassword); err != nil {
if err := client.Login(*flags.UserName, *flags.UserPassword); err != nil {
return nil, err
}

Expand Down
30 changes: 12 additions & 18 deletions benchmarks/gluon_bench/imap_benchmarks/server/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@ import (
"context"
"crypto/sha256"
"encoding/hex"
"entgo.io/ent/dialect"
"fmt"
"net"
"path/filepath"
"time"

"entgo.io/ent/dialect"
"github.com/ProtonMail/gluon"
"github.com/ProtonMail/gluon/benchmarks/gluon_bench/flags"
"github.com/ProtonMail/gluon/benchmarks/gluon_bench/utils"
"github.com/ProtonMail/gluon/connector"
"github.com/ProtonMail/gluon/imap"
"github.com/ProtonMail/gluon/profiling"
"github.com/ProtonMail/gluon/store"
_ "github.com/mattn/go-sqlite3"
Expand Down Expand Up @@ -52,7 +49,7 @@ func (*LocalServerBuilder) New(ctx context.Context, serverPath string, profiler
return nil, err
}

if err := addUser(ctx, server, serverPath, []string{utils.UserName}, utils.UserPassword); err != nil {
if err := addUser(ctx, server, serverPath); err != nil {
return nil, err
}

Expand All @@ -73,17 +70,14 @@ func (*LocalServerBuilder) New(ctx context.Context, serverPath string, profiler
}, nil
}

func addUser(ctx context.Context, server *gluon.Server, path string, addresses []string, password string) error {
hash := sha256.Sum256([]byte(addresses[0]))
func addUser(ctx context.Context, server *gluon.Server, path string) error {
hash := sha256.Sum256([]byte(*flags.UserName))
id := hex.EncodeToString(hash[:])
connector := connector.NewDummy(
addresses,
password,
time.Second,
imap.NewFlagSet(`\Answered`, `\Seen`, `\Flagged`, `\Deleted`),
imap.NewFlagSet(`\Answered`, `\Seen`, `\Flagged`, `\Deleted`),
imap.NewFlagSet(),
)

c, err := utils.NewConnector(*flags.Connector)
if err != nil {
return nil
}

storePath := filepath.Join(path, id+".store")
dbPath := filepath.Join(path, id+".db")
Expand All @@ -92,22 +86,22 @@ func addUser(ctx context.Context, server *gluon.Server, path string, addresses [
fmt.Printf("Adding user ID=%v\n BenchPath:'%v'\n DBPath:'%v'\n", id, storePath, dbPath)
}

store, err := store.NewOnDiskStore(storePath, []byte(utils.UserPassword))
store, err := store.NewOnDiskStore(storePath, []byte(*flags.UserPassword))
if err != nil {
return err
}

_, err = server.AddUser(
ctx,
connector,
c.Connector(),
store,
dialect.SQLite,
fmt.Sprintf("file:%v?cache=shared&_fk=1", dbPath))
if err != nil {
return err
}

if err := connector.Sync(context.Background()); err != nil {
if err := c.Sync(context.Background()); err != nil {
return err
}

Expand Down
21 changes: 11 additions & 10 deletions benchmarks/gluon_bench/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,22 @@ import (
"path/filepath"

"github.com/ProtonMail/gluon/benchmarks/gluon_bench/benchmark"
imap_benchmarks2 "github.com/ProtonMail/gluon/benchmarks/gluon_bench/imap_benchmarks"

"github.com/ProtonMail/gluon/benchmarks/gluon_bench/flags"
"github.com/ProtonMail/gluon/benchmarks/gluon_bench/gluon_benchmarks"
"github.com/ProtonMail/gluon/benchmarks/gluon_bench/imap_benchmarks"
"github.com/ProtonMail/gluon/benchmarks/gluon_bench/reporter"
)

var benches = []benchmark.Benchmark{
imap_benchmarks2.NewMailboxCreate(),
imap_benchmarks2.NewFetch(),
imap_benchmarks2.NewCopy(),
imap_benchmarks2.NewMove(),
imap_benchmarks2.NewStore(),
imap_benchmarks2.NewExpunge(),
imap_benchmarks2.NewSearchText(),
imap_benchmarks2.NewSearchSince(),
imap_benchmarks.NewMailboxCreate(),
imap_benchmarks.NewFetch(),
imap_benchmarks.NewCopy(),
imap_benchmarks.NewMove(),
imap_benchmarks.NewStore(),
imap_benchmarks.NewExpunge(),
imap_benchmarks.NewSearchText(),
imap_benchmarks.NewSearchSince(),
gluon_benchmarks.NewSync(),
}

func main() {
Expand Down
Loading

0 comments on commit b613808

Please sign in to comment.