Skip to content

Commit

Permalink
Fix short path
Browse files Browse the repository at this point in the history
  • Loading branch information
jlelse committed Jul 22, 2024
1 parent 8fdfeb3 commit b29854d
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 24 deletions.
2 changes: 1 addition & 1 deletion database.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type database struct {
// Other things
pc singleflight.Group // persistant cache
pcm sync.Mutex // post creation
sp singleflight.Group // singleflight group for short path requests
sp sync.Mutex // short path creation
debug bool
}

Expand Down
4 changes: 2 additions & 2 deletions postsFuncs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ func (a *goBlog) fullPostURL(p *post) string {

func (a *goBlog) shortPostURL(p *post) string {
s, err := a.db.shortenPath(p.Path)
if err != nil {
return p.Path
if err != nil || s == "" {
return a.getFullAddress(p.Path)
}
if a.cfg.Server.ShortPublicAddress != "" {
return a.cfg.Server.ShortPublicAddress + s
Expand Down
33 changes: 21 additions & 12 deletions shortPath.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@ func (db *database) shortenPath(p string) (string, error) {
return "", errors.New("empty path")
}

// Use singleflight to deduplicate concurrent requests and handle caching
v, err, _ := db.sp.Do(p, func() (interface{}, error) {
return db.shortenPathTransaction(p)
})
db.sp.Lock()
defer db.sp.Unlock()

result, err := db.shortenPathTransaction(p)
if err != nil {
return "", err
}

return v.(string), nil
return result, nil
}

func (db *database) shortenPathTransaction(p string) (string, error) {
Expand All @@ -33,14 +32,24 @@ func (db *database) shortenPathTransaction(p string) (string, error) {
var id int64
err = tx.QueryRow("select id from shortpath where path = @path", sql.Named("path", p)).Scan(&id)
if err == sql.ErrNoRows {
// Path doesn't exist, insert new entry
// Path doesn't exist, insert new entry with the lowest available id
result, err := tx.Exec(`
insert into shortpath (id, path)
values (
(select min(id) + 1 from (select id from shortpath union all select 0) where id + 1 not in (select id from shortpath)),
@path
)
`, sql.Named("path", p))
INSERT INTO shortpath (id, path)
VALUES (
(WITH RECURSIVE ids(n) AS (
SELECT 1
UNION ALL
SELECT n + 1 FROM ids
WHERE n < (SELECT COALESCE(MAX(id), 0) + 1 FROM shortpath)
)
SELECT n FROM ids
LEFT JOIN shortpath s ON ids.n = s.id
WHERE s.id IS NULL
ORDER BY n
LIMIT 1),
?
)
`, p)
if err != nil {
return "", err
}
Expand Down
25 changes: 16 additions & 9 deletions shortPath_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,35 @@ func Test_shortenPath(t *testing.T) {

res1, err := db.shortenPath("/a")
require.NoError(t, err)
assert.Equal(t, "/s/1", res1)

res2, err := db.shortenPath("/a")
require.NoError(t, err)
assert.Equal(t, "/s/1", res2)

res3, err := db.shortenPath("/b")
require.NoError(t, err)
assert.Equal(t, "/s/2", res3)

res4, err := db.shortenPath("/a")
require.NoError(t, err)
assert.Equal(t, "/s/1", res4)

assert.Equal(t, res1, res2)
assert.Equal(t, "/s/1", res1)
res5, err := db.shortenPath("/c")
require.NoError(t, err)
assert.Equal(t, "/s/3", res5)

assert.NotEqual(t, res1, res3)
assert.Equal(t, "/s/2", res3)
_, err = db.Exec("delete from shortpath where id = 2")
require.NoError(t, err)

assert.Equal(t, res2, res4)
assert.Equal(t, "/s/1", res4)
res6, err := db.shortenPath("/d")
require.NoError(t, err)
assert.Equal(t, "/s/2", res6)

_, _ = db.Exec("delete from shortpath where id = 1")
_, err = db.Exec("delete from shortpath where id = 1")
require.NoError(t, err)

res5, err := db.shortenPath("/c")
res7, err := db.shortenPath("/e")
require.NoError(t, err)
assert.Equal(t, "/s/1", res5)
assert.Equal(t, "/s/1", res7)
}

0 comments on commit b29854d

Please sign in to comment.