From bb185a0a3c4abd9da98ee6a0cd05916e1d1cbfe6 Mon Sep 17 00:00:00 2001 From: Umputun Date: Mon, 19 Mar 2018 01:38:38 -0500 Subject: [PATCH] optimize avatar partitioning, cover with test --- README.md | 4 +++- app/rest/auth/avatar.go | 9 +++++++-- app/rest/auth/avatar_test.go | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ac280b74..07630f2c 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Remark42 is a self-hosted, lightweight, and simple (yet functional) comment engi | --url | REMARK_URL | `https://remark42.com` | no | all | url to remark server | | --bolt | BOLTDB_PATH | `/tmp` | no | all | path to data directory | | --site | SITE | `remark` | yes | server | site name(s) | -| --admin | ADMIN | | yes | server | admin(s) names (user id) | +| --admin | ADMIN | | yes | server | admin names (list of user ids) | | --backup | BACKUP_PATH | `/tmp` | no | server | backups location | | --max-back | MAX_BACKUP_FILES | `10` | no | server | max backup files to keep | | --session | SESSION_STORE | `/tmp` | no | server | path to session store directory | @@ -50,6 +50,8 @@ Remark42 is a self-hosted, lightweight, and simple (yet functional) comment engi | --dbg | DEBUG | `false` | no | all | debug mode | | --dev-password | DEV_PASSWD | | no | all | password for `dev` user | +_all multi parameters separated by `,`_ + #### Run modes * `server` activates regular, server mode diff --git a/app/rest/auth/avatar.go b/app/rest/auth/avatar.go index 300fd5a4..abae9eba 100644 --- a/app/rest/auth/avatar.go +++ b/app/rest/auth/avatar.go @@ -9,6 +9,7 @@ import ( "os" "path" "strings" + "sync" "time" "github.com/go-chi/chi" @@ -25,6 +26,9 @@ type AvatarProxy struct { DefaultAvatar string RoutePath string RemarkURL string + + once sync.Once + ctcTable *crc64.Table } const imgSfx = ".image" @@ -122,14 +126,15 @@ func (p *AvatarProxy) Routes() (string, chi.Router) { // Default returns full default avatar url func (p *AvatarProxy) Default() string { - return strings.TrimRight(p.RemarkURL, "/") + p.RoutePath + "/" + p.DefaultAvatar + return path.Join(p.RemarkURL, p.RoutePath, p.DefaultAvatar) } // get location for user id by adding partion to final path in order to keep files // in different subdirectories and avoid too many files in a single place. // the end result is a full path like this - /tmp/avatars.test/92 func (p *AvatarProxy) location(id string) string { - checksum64 := crc64.Checksum([]byte(id), crc64.MakeTable(crc64.ECMA)) + p.once.Do(func() { p.ctcTable = crc64.MakeTable(crc64.ECMA) }) + checksum64 := crc64.Checksum([]byte(id), p.ctcTable) partition := checksum64 % 100 return path.Join(p.StorePath, fmt.Sprintf("%02d", partition)) } diff --git a/app/rest/auth/avatar_test.go b/app/rest/auth/avatar_test.go index a0631210..3ecbc285 100644 --- a/app/rest/auth/avatar_test.go +++ b/app/rest/auth/avatar_test.go @@ -106,3 +106,20 @@ func TestRoutesDefault(t *testing.T) { assert.NoError(t, err) assert.Equal(t, int64(10), sz) } + +func TestLocation(t *testing.T) { + p := AvatarProxy{StorePath: "/tmp/avatars.test"} + + tbl := []struct { + id string + res string + }{ + {"abc", "/tmp/avatars.test/35"}, + {"xyz", "/tmp/avatars.test/69"}, + {"blah blah", "/tmp/avatars.test/29"}, + } + + for i, tt := range tbl { + assert.Equal(t, tt.res, p.location(tt.id), "test #%d", i) + } +}