Skip to content

Commit 9dacb52

Browse files
committed
Our existing code created prepared statements without finalizing them.
This changes those to properly dispose of them. A future improvement is to only prepare the EXPORT statement once, and attach it to the Session or store.
1 parent aedc2f5 commit 9dacb52

File tree

1 file changed

+85
-62
lines changed

1 file changed

+85
-62
lines changed

packages/memory/space.ts

Lines changed: 85 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -414,24 +414,29 @@ const recall = <Space extends MemorySpace>(
414414
{ store }: Session<Space>,
415415
{ the, of }: { the: MIME; of: URI },
416416
): Revision<Fact> | null => {
417-
const row = store.prepare(EXPORT).get({ the, of }) as StateRow | undefined;
418-
if (row) {
419-
const revision: Revision<Fact> = {
420-
the,
421-
of,
422-
cause: row.cause
423-
? (fromString(row.cause) as Reference<Assertion>)
424-
: refer(unclaimed({ the, of })),
425-
since: row.since,
426-
};
417+
const stmt = store.prepare(EXPORT);
418+
try {
419+
const row = stmt.get({ the, of }) as StateRow | undefined;
420+
if (row) {
421+
const revision: Revision<Fact> = {
422+
the,
423+
of,
424+
cause: row.cause
425+
? (fromString(row.cause) as Reference<Assertion>)
426+
: refer(unclaimed({ the, of })),
427+
since: row.since,
428+
};
427429

428-
if (row.is) {
429-
revision.is = JSON.parse(row.is);
430-
}
430+
if (row.is) {
431+
revision.is = JSON.parse(row.is);
432+
}
431433

432-
return revision;
433-
} else {
434-
return null;
434+
return revision;
435+
} else {
436+
return null;
437+
}
438+
} finally {
439+
stmt.finalize();
435440
}
436441
};
437442

@@ -457,20 +462,25 @@ const _causeChain = <Space extends MemorySpace>(
457462
excludeFact: string | undefined,
458463
): Revision<Fact>[] => {
459464
const { store } = session;
460-
const rows = store.prepare(CAUSE_CHAIN).all({ of, the }) as CauseRow[];
461-
const revisions = [];
462-
if (rows && rows.length) {
463-
for (const result of rows) {
464-
if (result.fact === excludeFact) {
465-
continue;
466-
}
467-
const revision = getFact(session, { fact: result.fact });
468-
if (revision) {
469-
revisions.push(revision);
465+
const stmt = store.prepare(CAUSE_CHAIN);
466+
try {
467+
const rows = stmt.all({ of, the }) as CauseRow[];
468+
const revisions = [];
469+
if (rows && rows.length) {
470+
for (const result of rows) {
471+
if (result.fact === excludeFact) {
472+
continue;
473+
}
474+
const revision = getFact(session, { fact: result.fact });
475+
if (revision) {
476+
revisions.push(revision);
477+
}
470478
}
471479
}
480+
return revisions;
481+
} finally {
482+
stmt.finalize();
472483
}
473-
return revisions;
474484
};
475485

476486
/**
@@ -485,26 +495,31 @@ const getFact = <Space extends MemorySpace>(
485495
{ store }: Session<Space>,
486496
{ fact }: { fact: string },
487497
): Revision<Fact> | undefined => {
488-
const row = store.prepare(GET_FACT).get({ fact }) as StateRow | undefined;
489-
if (row === undefined) {
490-
return undefined;
491-
}
492-
// It's possible to have more than one matching fact, but since the fact's id
493-
// incorporates its cause chain, we would have to have issued a retraction,
494-
// followed by the same chain of facts. At that point, it really is the same.
495-
// Since `the` and `of` are part of the fact reference, they are also unique.
496-
const revision: Revision<Fact> = {
497-
the: row.the as MIME,
498-
of: row.of as URI,
499-
cause: row.cause
500-
? (fromString(row.cause) as Reference<Assertion>)
501-
: refer(unclaimed(row as FactAddress)),
502-
since: row.since,
503-
};
504-
if (row.is) {
505-
revision.is = JSON.parse(row.is);
498+
const stmt = store.prepare(GET_FACT);
499+
try {
500+
const row = stmt.get({ fact }) as StateRow | undefined;
501+
if (row === undefined) {
502+
return undefined;
503+
}
504+
// It's possible to have more than one matching fact, but since the fact's id
505+
// incorporates its cause chain, we would have to have issued a retraction,
506+
// followed by the same chain of facts. At that point, it really is the same.
507+
// Since `the` and `of` are part of the fact reference, they are also unique.
508+
const revision: Revision<Fact> = {
509+
the: row.the as MIME,
510+
of: row.of as URI,
511+
cause: row.cause
512+
? (fromString(row.cause) as Reference<Assertion>)
513+
: refer(unclaimed(row as FactAddress)),
514+
since: row.since,
515+
};
516+
if (row.is) {
517+
revision.is = JSON.parse(row.is);
518+
}
519+
return revision;
520+
} finally {
521+
stmt.finalize();
506522
}
507-
return revision;
508523
};
509524

510525
const select = <Space extends MemorySpace>(
@@ -566,24 +581,30 @@ const toFact = function (row: StateRow): SelectedFact {
566581
};
567582

568583
// Select facts matching the selector. Facts are ordered by since.
569-
export const selectFacts = function* <Space extends MemorySpace>(
584+
export const selectFacts = function <Space extends MemorySpace>(
570585
{ store }: Session<Space>,
571586
{ the, of, cause, is, since }: FactSelector,
572-
): Iterable<SelectedFact> {
587+
): SelectedFact[] {
573588
const stmt = store.prepare(EXPORT);
574-
// Note: Cannot finalize() in a generator function's finally block because
575-
// the finally block runs when the generator returns (immediately), not when
576-
// it's exhausted. The statement will be finalized when the store is closed.
577-
for (
578-
const row of stmt.iter({
579-
the: the === SelectAllString ? null : the,
580-
of: of === SelectAllString ? null : of,
581-
cause: cause === SelectAllString ? null : cause,
582-
is: is === undefined ? null : {},
583-
since: since ?? null,
584-
}) as Iterable<StateRow>
585-
) {
586-
yield toFact(row);
589+
try {
590+
const results = [];
591+
// Note: Cannot finalize() in a generator function's finally block because
592+
// the finally block runs when the generator returns (immediately), not when
593+
// it's exhausted. The statement will be finalized when the store is closed.
594+
for (
595+
const row of stmt.iter({
596+
the: the === SelectAllString ? null : the,
597+
of: of === SelectAllString ? null : of,
598+
cause: cause === SelectAllString ? null : cause,
599+
is: is === undefined ? null : {},
600+
since: since ?? null,
601+
}) as Iterable<StateRow>
602+
) {
603+
results.push(toFact(row));
604+
}
605+
return results;
606+
} finally {
607+
stmt.finalize();
587608
}
588609
};
589610

@@ -763,9 +784,11 @@ const commit = <Space extends MemorySpace>(
763784
): Commit<Space> => {
764785
const the = COMMIT_LOG_TYPE;
765786
const of = transaction.sub;
766-
const row = session.store.prepare(EXPORT).get({ the, of }) as
787+
const stmt = session.store.prepare(EXPORT);
788+
const row = stmt.get({ the, of }) as
767789
| StateRow
768790
| undefined;
791+
stmt.finalize();
769792

770793
const [since, cause] = row
771794
? [

0 commit comments

Comments
 (0)