|
1 | 1 | 'use strict'; |
| 2 | +// Flags: --expose-gc |
| 3 | + |
2 | 4 | const { skipIfSQLiteMissing } = require('../common'); |
3 | 5 | skipIfSQLiteMissing(); |
4 | 6 |
|
@@ -135,3 +137,35 @@ test('sql error messages are descriptive', () => { |
135 | 137 | message: /no such table/i, |
136 | 138 | }); |
137 | 139 | }); |
| 140 | + |
| 141 | +test('a tag store keeps the database alive by itself', () => { |
| 142 | + const sql = new DatabaseSync(':memory:').createTagStore(); |
| 143 | + |
| 144 | + sql.db.exec('CREATE TABLE test (data INTEGER)'); |
| 145 | + |
| 146 | + global.gc(); |
| 147 | + |
| 148 | + // eslint-disable-next-line no-unused-expressions |
| 149 | + sql.run`INSERT INTO test (data) VALUES (1)`; |
| 150 | +}); |
| 151 | + |
| 152 | +test('tag store prevents circular reference leaks', async () => { |
| 153 | + const { gcUntil } = require('../common/gc'); |
| 154 | + |
| 155 | + const before = process.memoryUsage().heapUsed; |
| 156 | + |
| 157 | + // Create many SQLTagStore + DatabaseSync pairs with circular references |
| 158 | + for (let i = 0; i < 1000; i++) { |
| 159 | + const sql = new DatabaseSync(':memory:').createTagStore(); |
| 160 | + sql.db.exec('CREATE TABLE test (data INTEGER)'); |
| 161 | + // eslint-disable-next-line no-void |
| 162 | + sql.db.setAuthorizer(() => void sql.db); |
| 163 | + } |
| 164 | + |
| 165 | + // GC until memory stabilizes or give up after 20 attempts |
| 166 | + await gcUntil('tag store leak check', () => { |
| 167 | + const after = process.memoryUsage().heapUsed; |
| 168 | + // Memory should not grow significantly (allow 50% margin for noise) |
| 169 | + return after < before * 1.5; |
| 170 | + }, 20); |
| 171 | +}); |
0 commit comments