1 | #include "catch.hpp" |
2 | #include "duckdb/common/file_system.hpp" |
3 | #include "test_helpers.hpp" |
4 | |
5 | using namespace duckdb; |
6 | using namespace std; |
7 | |
8 | TEST_CASE("Test that database size does not grow after many checkpoints" , "[storage][.]" ) { |
9 | constexpr idx_t VALUE_COUNT = 10000; |
10 | idx_t expected_sum = 0; |
11 | |
12 | FileSystem fs; |
13 | auto config = GetTestConfig(); |
14 | unique_ptr<DuckDB> database; |
15 | unique_ptr<QueryResult> result; |
16 | auto storage_database = TestCreatePath("dbsize_test" ); |
17 | |
18 | // make sure the database does not exist |
19 | DeleteDatabase(storage_database); |
20 | { |
21 | // create a database and insert values |
22 | DuckDB db(storage_database); |
23 | Connection con(db); |
24 | REQUIRE_NO_FAIL(con.Query("BEGIN TRANSACTION;" )); |
25 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test(a INTEGER);" )); |
26 | for (idx_t i = 0; i < VALUE_COUNT; i++) { |
27 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES (" + to_string(i) + ");" )); |
28 | expected_sum += i; |
29 | } |
30 | REQUIRE_NO_FAIL(con.Query("COMMIT;" )); |
31 | result = con.Query("SELECT SUM(a) FROM test" ); |
32 | REQUIRE(CHECK_COLUMN(result, 0, {Value::BIGINT(expected_sum)})); |
33 | } |
34 | // force a checkpoint by reloading |
35 | { |
36 | DuckDB db(storage_database, config.get()); |
37 | Connection con(db); |
38 | } |
39 | |
40 | // get the size of the database |
41 | int64_t size; |
42 | { |
43 | auto handle = fs.OpenFile(storage_database, FileFlags::READ); |
44 | size = fs.GetFileSize(*handle); |
45 | REQUIRE(size >= 0); |
46 | } |
47 | // now reload the database a bunch of times, and everytime we reload update all the values |
48 | for (idx_t i = 0; i < 20; i++) { |
49 | DuckDB db(storage_database, config.get()); |
50 | Connection con(db); |
51 | // verify the current count |
52 | result = con.Query("SELECT SUM(a) FROM test" ); |
53 | REQUIRE(CHECK_COLUMN(result, 0, {Value::BIGINT(expected_sum)})); |
54 | // update the table |
55 | REQUIRE_NO_FAIL(con.Query("UPDATE test SET a=a+1;" )); |
56 | expected_sum += VALUE_COUNT; |
57 | // verify the current count again |
58 | result = con.Query("SELECT SUM(a) FROM test" ); |
59 | REQUIRE(CHECK_COLUMN(result, 0, {Value::BIGINT(expected_sum)})); |
60 | } |
61 | // get the new file size |
62 | int64_t new_size; |
63 | { |
64 | auto handle = fs.OpenFile(storage_database, FileFlags::READ); |
65 | new_size = fs.GetFileSize(*handle); |
66 | REQUIRE(new_size >= 0); |
67 | } |
68 | // require that the size did not grow more than factor 3 |
69 | // we allow the database file to grow somewhat because there will be empty blocks inside the file after many |
70 | // checkpoints however this should never be more than factor ~2.5 the original database size |
71 | REQUIRE(new_size <= size * 3); |
72 | DeleteDatabase(storage_database); |
73 | } |
74 | |