| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e62608b commit 45d25c4
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2819,6 +2819,7 @@ BaseObjectPtr<SQLTagStore> SQLTagStore::Create( | |||
| 2819 | 2819 | .ToLocal(&obj)) { | |
| 2820 | 2820 | return nullptr; | |
| 2821 | 2821 | } | |
| 2822 | + obj->SetInternalField(kDatabaseObject, database->object()); | ||
| 2822 | 2823 | return MakeBaseObject<SQLTagStore>(env, obj, std::move(database), capacity); | |
| 2823 | 2824 | } | |
| 2824 | 2825 | ||
@@ -2829,9 +2830,8 @@ void SQLTagStore::CapacityGetter(const FunctionCallbackInfo<Value>& args) { | |||
| 2829 | 2830 | } | |
| 2830 | 2831 | ||
| 2831 | 2832 | void SQLTagStore::DatabaseGetter(const FunctionCallbackInfo<Value>& args) { | |
| 2832 | - SQLTagStore* store; | ||
| 2833 | - ASSIGN_OR_RETURN_UNWRAP(&store, args.This()); | ||
| 2834 | - args.GetReturnValue().Set(store->database_->object()); | ||
| 2833 | + args.GetReturnValue().Set( | ||
| 2834 | + args.This()->GetInternalField(kDatabaseObject).As<Value>()); | ||
| 2835 | 2835 | } | |
| 2836 | 2836 | ||
| 2837 | 2837 | void SQLTagStore::SizeGetter(const FunctionCallbackInfo<Value>& args) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -305,6 +305,11 @@ class Session : public BaseObject { | |||
| 305 | 305 | ||
| 306 | 306 | class SQLTagStore : public BaseObject { | |
| 307 | 307 | public: | |
| 308 | + enum InternalFields { | ||
| 309 | + kDatabaseObject = BaseObject::kInternalFieldCount, | ||
| 310 | + kInternalFieldCount | ||
| 311 | + }; | ||
| 312 | + | ||
| 308 | 313 | SQLTagStore(Environment* env, | |
| 309 | 314 | v8::Local<v8::Object> object, | |
| 310 | 315 | BaseObjectWeakPtr<DatabaseSync> database, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,6 @@ | |||
| 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 | + }); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments