3
0

Change pkg/id to utilize channels for better performance

This commit is contained in:
Tomaž Jerman
2024-01-08 10:09:05 +01:00
parent 1f415be2db
commit 8031e2093a
3 changed files with 83 additions and 23 deletions
+4
View File
@@ -27,6 +27,7 @@ import (
"github.com/cortezaproject/corteza/server/pkg/eventbus"
"github.com/cortezaproject/corteza/server/pkg/healthcheck"
"github.com/cortezaproject/corteza/server/pkg/http"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/locale"
"github.com/cortezaproject/corteza/server/pkg/logger"
"github.com/cortezaproject/corteza/server/pkg/mail"
@@ -293,6 +294,9 @@ func (app *CortezaApp) InitServices(ctx context.Context) (err error) {
return nil
}
// @todo place this somewhere better
id.Init(ctx)
err = app.initEnvoy(ctx, app.Log)
if err != nil {
return
+63 -23
View File
@@ -1,11 +1,14 @@
package id
import (
"context"
"fmt"
"github.com/sony/sonyflake"
"os"
"strconv"
"sync"
"time"
"github.com/sony/sonyflake"
)
const (
@@ -33,54 +36,91 @@ const (
// envKeySimpleIncrement = "SONYFLAKE_SIMPLE_INCREMENT"
)
var sf *sonyflake.Sonyflake
var (
initialized bool
idQueue = make(chan uint64, 512)
makerCount = 20
)
func init() {
if err := initSonyflake(); err != nil {
panic(fmt.Errorf("sonyflake init failed: %w", err))
func Init(ctx context.Context) {
if initialized {
return
}
initialized = true
wg := &sync.WaitGroup{}
wg.Add(makerCount)
for i := 0; i < makerCount; i++ {
makeIDer(ctx, wg, idQueue, uint64(i+1))
}
wg.Wait()
}
func initSonyflake() error {
func makeIDer(ctx context.Context, wg *sync.WaitGroup, qq chan uint64, thr uint64) {
go func() {
ss, err := initSonyflake(thr)
if err != nil {
panic(fmt.Errorf("sonyflake init failed: %w", err))
}
wg.Done()
for {
select {
case <-ctx.Done():
return
default:
id, err := ss.NextID()
if err != nil {
panic(err)
}
qq <- id
}
}
}()
}
func initSonyflake(thr uint64) (out *sonyflake.Sonyflake, err error) {
settings := sonyflake.Settings{
StartTime: time.Unix(jan1st2017, 0),
}
// check if SONYFLAKE_MACHINE_ID is set and create
// MachineID function that returns it
var id uint64
if machineID := os.Getenv(envKeyMachineID); machineID != "" {
// check if machineID is a valid uint16
if id, err := strconv.ParseUint(machineID, 10, 16); err != nil {
if id, err = strconv.ParseUint(machineID, 10, 16); err != nil {
// should crash right away
return fmt.Errorf(
err = fmt.Errorf(
"could not use %s (%s), expecting uint16 (0..65535): %w",
envKeyMachineID,
machineID,
err,
)
return
} else {
settings.MachineID = func() (uint16, error) {
return uint16(id), nil
return uint16(id + thr), nil
}
}
} else if thr > 0 {
settings.MachineID = func() (uint16, error) {
return uint16(thr), nil
}
}
sf = sonyflake.NewSonyflake(settings)
_, err := sf.NextID()
return err
}
out = sonyflake.NewSonyflake(settings)
_, err = out.NextID()
// NextID returns uint64 ID, or panics
//
// See https://github.com/sony/sonyflake for details
func nextSonyflake() uint64 {
if id, err := sf.NextID(); err != nil {
panic(err)
} else {
return id
}
return
}
func Next() uint64 {
return nextSonyflake()
if !initialized {
panic("ID generator not initialized: call pkg/id.Init")
}
return <-idQueue
}
+16
View File
@@ -0,0 +1,16 @@
package id
import (
"testing"
"github.com/cortezaproject/corteza/server/pkg/cli"
)
func BenchmarkGenerator(b *testing.B) {
ctx := cli.Context()
Init(ctx)
for n := 0; n < b.N; n++ {
Next()
}
}