Skip to content

Commit 4a6c05e

Browse files
committed
feat: add a method to compute the DB size of the state
Part of siderolabs/omni#2140 Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
1 parent 6511e9d commit 4a6c05e

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

pkg/state/impl/sqlite/size.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
package sqlite
6+
7+
import (
8+
"context"
9+
"fmt"
10+
11+
"zombiezen.com/go/sqlite"
12+
13+
"github.com/cosi-project/state-sqlite/pkg/sqlitexx"
14+
)
15+
16+
// DBSize returns the size in bytes of tables used by this package.
17+
//
18+
// It uses SQLite's dbstat virtual table to calculate the size of the
19+
// resources and events tables within the main database file (logical
20+
// table page usage), which does not include any separate WAL/SHM files.
21+
func (st *State) DBSize(ctx context.Context) (int64, error) {
22+
conn, err := st.db.Take(ctx)
23+
if err != nil {
24+
return 0, fmt.Errorf("error taking connection for db size: %w", err)
25+
}
26+
27+
defer st.db.Put(conn)
28+
29+
var size int64
30+
31+
q, err := sqlitexx.NewQuery(
32+
conn,
33+
`SELECT coalesce(SUM(pgsize), 0) AS total_size FROM dbstat WHERE name = $table1 OR name = $table2`,
34+
)
35+
if err != nil {
36+
return 0, fmt.Errorf("preparing query for db size: %w", err)
37+
}
38+
39+
if err = q.
40+
BindString("$table1", st.options.TablePrefix+"resources").
41+
BindString("$table2", st.options.TablePrefix+"events").
42+
QueryRow(
43+
func(stmt *sqlite.Stmt) error {
44+
size = stmt.GetInt64("total_size")
45+
46+
return nil
47+
},
48+
); err != nil {
49+
return 0, fmt.Errorf("failed to get db size: %w", err)
50+
}
51+
52+
return size, nil
53+
}

pkg/state/impl/sqlite/size_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
package sqlite_test
6+
7+
import (
8+
"strconv"
9+
"testing"
10+
11+
"github.com/cosi-project/runtime/pkg/state/conformance"
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
15+
"github.com/cosi-project/state-sqlite/pkg/state/impl/sqlite"
16+
)
17+
18+
func TestDBSizeEmpty(t *testing.T) {
19+
t.Parallel()
20+
21+
withSqliteCore(t, func(st *sqlite.State) {
22+
size, err := st.DBSize(t.Context())
23+
require.NoError(t, err)
24+
assert.Greater(t, size, int64(0), "even empty tables should have some overhead")
25+
})
26+
}
27+
28+
func TestDBSizeGrowsWithData(t *testing.T) {
29+
t.Parallel()
30+
31+
withSqliteCore(t, func(st *sqlite.State) {
32+
sizeBefore, err := st.DBSize(t.Context())
33+
require.NoError(t, err)
34+
35+
for i := range 100 {
36+
require.NoError(t, st.Create(t.Context(), conformance.NewPathResource("ns1", strconv.Itoa(i))))
37+
}
38+
39+
sizeAfter, err := st.DBSize(t.Context())
40+
require.NoError(t, err)
41+
42+
assert.Greater(t, sizeAfter, sizeBefore, "size should grow after inserting resources")
43+
})
44+
}

0 commit comments

Comments
 (0)