mirror of
https://github.com/multipleof4/ntfy.git
synced 2026-10-08 21:05:21 +00:00
Fix exact count that caused the RO replicate to fall over...
This commit is contained in:
+2
-1
@@ -300,7 +300,8 @@ func (c *Cache) MarkPublished(m *model.Message) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MessagesCount returns the total number of messages in the cache
|
// MessagesCount returns the total number of messages in the cache. On Postgres, this is the
|
||||||
|
// planner's estimate once the table has been analyzed, not an exact count.
|
||||||
func (c *Cache) MessagesCount() (int, error) {
|
func (c *Cache) MessagesCount() (int, error) {
|
||||||
rows, err := c.db.ReadOnly().Query(c.queries.selectMessagesCount)
|
rows, err := c.db.ReadOnly().Query(c.queries.selectMessagesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -62,7 +62,12 @@ const (
|
|||||||
ORDER BY time, id
|
ORDER BY time, id
|
||||||
`
|
`
|
||||||
postgresUpdateMessagePublishedQuery = `UPDATE message SET published = TRUE WHERE mid = $1`
|
postgresUpdateMessagePublishedQuery = `UPDATE message SET published = TRUE WHERE mid = $1`
|
||||||
postgresSelectMessagesCountQuery = `SELECT COUNT(*) FROM message`
|
// Planner estimate, since a COUNT(*) scans the whole table; reltuples is -1 if never analyzed
|
||||||
|
postgresSelectMessagesCountQuery = `
|
||||||
|
SELECT CASE WHEN reltuples < 0 THEN (SELECT COUNT(*) FROM message) ELSE reltuples::BIGINT END
|
||||||
|
FROM pg_class
|
||||||
|
WHERE oid = 'message'::regclass
|
||||||
|
`
|
||||||
postgresSelectTopicsQuery = `SELECT topic FROM message GROUP BY topic`
|
postgresSelectTopicsQuery = `SELECT topic FROM message GROUP BY topic`
|
||||||
|
|
||||||
postgresDeleteExpiredMessagesQuery = `DELETE FROM message WHERE mid IN (SELECT mid FROM message WHERE expires <= $1 AND published = TRUE LIMIT $2)`
|
postgresDeleteExpiredMessagesQuery = `DELETE FROM message WHERE mid IN (SELECT mid FROM message WHERE expires <= $1 AND published = TRUE LIMIT $2)`
|
||||||
|
|||||||
@@ -74,3 +74,28 @@ func TestPostgresStore_Migration_From14(t *testing.T) {
|
|||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, dbtest.PostgresSchema(t, freshDB), dbtest.PostgresSchema(t, testDB))
|
require.Equal(t, dbtest.PostgresSchema(t, freshDB), dbtest.PostgresSchema(t, testDB))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPostgresStore_MessagesCount_UsesPlannerEstimate(t *testing.T) {
|
||||||
|
// The manager calls MessagesCount every minute for a metric; a COUNT(*) scans the whole
|
||||||
|
// table on every call, so once the table has been analyzed, the planner's estimate is used
|
||||||
|
testDB := dbtest.CreateTestPostgres(t)
|
||||||
|
store, err := message.NewPostgresStore(testDB, 0, 0)
|
||||||
|
require.Nil(t, err)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
require.Nil(t, store.AddMessage(model.NewDefaultMessage("mytopic", "some message")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Never analyzed: falls back to an exact count
|
||||||
|
count, err := store.MessagesCount()
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, 10, count)
|
||||||
|
|
||||||
|
// Analyzed, then rows deleted: the estimate lags until the next (auto)analyze
|
||||||
|
_, err = testDB.Exec(`ANALYZE message`)
|
||||||
|
require.Nil(t, err)
|
||||||
|
_, err = testDB.Exec(`DELETE FROM message WHERE id IN (SELECT id FROM message LIMIT 4)`)
|
||||||
|
require.Nil(t, err)
|
||||||
|
count, err = store.MessagesCount()
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, 10, count)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user