diff --git a/api/auth_middleware.go b/api/auth_middleware.go index 7c87e6f0..b46851c3 100644 --- a/api/auth_middleware.go +++ b/api/auth_middleware.go @@ -33,15 +33,20 @@ func (app *ApiServer) recoverAuthorityFromSignatureHeaders(c *fiber.Ctx) (int32, recoveredAddr := crypto.PubkeyToAddress(*publicKey) walletLower := strings.ToLower(recoveredAddr.Hex()) + // check cache + if hit, ok := app.resolveWalletCache.Get(walletLower); ok { + return hit, walletLower + } + var userId int32 err = app.pool.QueryRow( c.Context(), ` - SELECT user_id FROM users + SELECT user_id FROM users WHERE - wallet = $1 - AND is_current = true - ORDER BY handle_lc IS NOT NULL, created_at ASC + wallet = $1 + AND is_current = true + ORDER BY handle_lc IS NOT NULL, created_at ASC LIMIT 1 `, walletLower, @@ -51,6 +56,8 @@ func (app *ApiServer) recoverAuthorityFromSignatureHeaders(c *fiber.Ctx) (int32, return 0, walletLower } + app.resolveWalletCache.Set(walletLower, userId) + return userId, walletLower } diff --git a/api/server.go b/api/server.go index 00a7da87..560415fd 100644 --- a/api/server.go +++ b/api/server.go @@ -20,6 +20,7 @@ import ( pgxzap "github.com/jackc/pgx-zap" "github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/tracelog" + "github.com/maypok86/otter" "github.com/segmentio/encoding/json" "go.uber.org/zap" "go.uber.org/zap/zapcore" @@ -80,19 +81,35 @@ func NewApiServer(config config.Config) *ApiServer { pool, err := pgxpool.NewWithConfig(context.Background(), connConfig) if err != nil { - logger.Error("db connect failed", zap.Error(err)) + logger.Fatal("db connect failed", zap.Error(err)) + } + + resolveHandleCache, err := otter.MustBuilder[string, int32](50_000). + CollectStats(). + Build() + if err != nil { + panic(err) + } + + resolveWalletCache, err := otter.MustBuilder[string, int32](50_000). + CollectStats(). + Build() + if err != nil { + panic(err) } app := &ApiServer{ - fiber.New(fiber.Config{ + App: fiber.New(fiber.Config{ JSONEncoder: json.Marshal, JSONDecoder: json.Unmarshal, ErrorHandler: errorHandler(logger), }), - pool, - dbv1.New(pool), - logger, - time.Now(), + pool: pool, + queries: dbv1.New(pool), + logger: logger, + started: time.Now(), + resolveHandleCache: resolveHandleCache, + resolveWalletCache: resolveWalletCache, } app.Use(recover.New(recover.Config{ @@ -218,10 +235,12 @@ func NewApiServer(config config.Config) *ApiServer { type ApiServer struct { *fiber.App - pool *pgxpool.Pool - queries *dbv1.Queries - logger *zap.Logger - started time.Time + pool *pgxpool.Pool + queries *dbv1.Queries + logger *zap.Logger + started time.Time + resolveHandleCache otter.Cache[string, int32] + resolveWalletCache otter.Cache[string, int32] } func (app *ApiServer) home(c *fiber.Ctx) error { @@ -246,10 +265,13 @@ func decodeIdList(c *fiber.Ctx) []int32 { } func (app *ApiServer) resolveUserHandleToId(handle string) (int32, error) { - // todo: can do some in memory cache here + if hit, ok := app.resolveHandleCache.Get(handle); ok { + return hit, nil + } var userId int32 sql := `select user_id from users where handle_lc = lower($1)` err := app.pool.QueryRow(context.Background(), sql, handle).Scan(&userId) + app.resolveHandleCache.Set(handle, userId) return userId, err } diff --git a/go.mod b/go.mod index 0a60c46c..3a45bcae 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/jackc/pgx-zap v0.0.0-20221202020421-94b1cb2f889f github.com/jackc/pgx/v5 v5.7.4 github.com/joho/godotenv v1.5.1 + github.com/maypok86/otter v1.2.4 github.com/segmentio/encoding v0.4.1 github.com/speps/go-hashids/v2 v2.0.1 github.com/stretchr/testify v1.10.0 @@ -33,9 +34,11 @@ require ( github.com/cosmos/gogoproto v1.7.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect + github.com/dolthub/maphash v0.1.0 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect + github.com/gammazero/deque v1.0.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.2 // indirect diff --git a/go.sum b/go.sum index ba1efd5c..a8d9ab3f 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,8 @@ github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ= +github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= github.com/ethereum/go-ethereum v1.15.8 h1:H6NilvRXFVoHiXZ3zkuTqKW5XcxjLZniV5UjxJt1GJU= github.com/ethereum/go-ethereum v1.15.8/go.mod h1:+S9k+jFzlyVTNcYGvqFhzN/SFhI6vA+aOY4T5tLSPL0= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -39,6 +41,8 @@ github.com/gagliardetto/solana-go v1.12.0 h1:rzsbilDPj6p+/DOPXBMLhwMZeBgeRuXjm5z github.com/gagliardetto/solana-go v1.12.0/go.mod h1:l/qqqIN6qJJPtxW/G1PF4JtcE3Zg2vD2EliZrr9Gn5k= github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw= github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= +github.com/gammazero/deque v1.0.0 h1:LTmimT8H7bXkkCy6gZX7zNLtkbz4NdS2z8LZuor3j34= +github.com/gammazero/deque v1.0.0/go.mod h1:iflpYvtGfM3U8S8j+sZEKIak3SAKYpA5/SQewgfXDKo= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= @@ -99,6 +103,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/maypok86/otter v1.2.4 h1:HhW1Pq6VdJkmWwcZZq19BlEQkHtI8xgsQzBVXJU0nfc= +github.com/maypok86/otter v1.2.4/go.mod h1:mKLfoI7v1HOmQMwFgX4QkRk23mX6ge3RDvjdHOWG4R4= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=