Skip to content

Commit 5454383

Browse files
committed
[BUGFIX #484] Improve NestedTransaction handling
* ensure running `commit` always clears the current transaction * if we begin a transaction with an existing transaction warn, commit it, then start begin the next.
1 parent 414f9be commit 5454383

File tree

3 files changed

+50
-17
lines changed

3 files changed

+50
-17
lines changed

packages/@glimmer/runtime/lib/environment.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ export abstract class Environment {
330330
}
331331

332332
begin() {
333-
assert(!this._transaction, 'Cannot start a nested transaction');
333+
assert(!this._transaction, 'a glimmer transaction was begun, but one already exists. You may have a nested transaction');
334334
this._transaction = new Transaction();
335335
}
336336

@@ -359,8 +359,9 @@ export abstract class Environment {
359359
}
360360

361361
commit() {
362-
this.transaction.commit();
362+
let transaction = this.transaction;
363363
this._transaction = null;
364+
transaction.commit();
364365
}
365366

366367
attributeFor(element: Simple.Element, attr: string, isTrusting: boolean, namespace?: string): AttributeManager {

packages/@glimmer/runtime/lib/opcodes.ts

+16-15
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,7 @@ export const enum Op {
893893
}
894894

895895
export function debugSlice(env: Environment, start: number, end: number) {
896+
return;
896897
if (!CI && DEBUG) {
897898
/* tslint:disable:no-console */
898899
let { program, constants } = env;
@@ -1073,24 +1074,24 @@ export class AppendOpcodes {
10731074

10741075
evaluate(vm: VM, opcode: Opcode, type: number) {
10751076
let func = this.evaluateOpcode[type];
1076-
if (!CI && DEBUG) {
1077-
/* tslint:disable */
1078-
let [name, params] = debug(vm.constants, opcode.type, opcode.op1, opcode.op2, opcode.op3);
1079-
console.log(`${vm['pc'] - 4}. ${logOpcode(name, params)}`);
1080-
// console.log(...debug(vm.constants, type, opcode.op1, opcode.op2, opcode.op3));
1081-
/* tslint:enable */
1082-
}
1077+
// if (!CI && DEBUG) {
1078+
// /* tslint:disable */
1079+
// let [name, params] = debug(vm.constants, opcode.type, opcode.op1, opcode.op2, opcode.op3);
1080+
// console.log(`${vm['pc'] - 4}. ${logOpcode(name, params)}`);
1081+
// // console.log(...debug(vm.constants, type, opcode.op1, opcode.op2, opcode.op3));
1082+
// /* tslint:enable */
1083+
// }
10831084

10841085
func(vm, opcode);
10851086

1086-
if (!CI && DEBUG) {
1087-
/* tslint:disable */
1088-
console.log('%c -> pc: %d, ra: %d, fp: %d, sp: %d, s0: %O, s1: %O, t0: %O, t1: %O', 'color: orange', vm['pc'], vm['ra'], vm['fp'], vm['sp'], vm['s0'], vm['s1'], vm['t0'], vm['t1']);
1089-
console.log('%c -> eval stack', 'color: red', vm.stack.toArray());
1090-
console.log('%c -> scope', 'color: green', vm.scope()['slots'].map(s => s && s['value'] ? s['value']() : s));
1091-
console.log('%c -> elements', 'color: blue', vm.elements()['elementStack'].toArray());
1092-
/* tslint:enable */
1093-
}
1087+
// if (!CI && DEBUG) {
1088+
// /* tslint:disable */
1089+
// console.log('%c -> pc: %d, ra: %d, fp: %d, sp: %d, s0: %O, s1: %O, t0: %O, t1: %O', 'color: orange', vm['pc'], vm['ra'], vm['fp'], vm['sp'], vm['s0'], vm['s1'], vm['t0'], vm['t1']);
1090+
// console.log('%c -> eval stack', 'color: red', vm.stack.toArray());
1091+
// console.log('%c -> scope', 'color: green', vm.scope()['slots'].map(s => s && s['value'] ? s['value']() : s));
1092+
// console.log('%c -> elements', 'color: blue', vm.elements()['elementStack'].toArray());
1093+
// /* tslint:enable */
1094+
// }
10941095
}
10951096
}
10961097

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { TestEnvironment } from "@glimmer/test-helpers";
2+
3+
QUnit.module('env');
4+
5+
QUnit.test('assert against nested transactions', assert => {
6+
let env = new TestEnvironment();
7+
env.begin();
8+
assert.throws(() => env.begin(), 'a glimmer transaction was begun, but one already exists. You may have a nested transaction');
9+
});
10+
11+
QUnit.test('ensure commit cleans up when it can', assert => {
12+
let env = new TestEnvironment();
13+
env.begin();
14+
15+
// ghetto stub
16+
Object.defineProperty(env, 'transaction', {
17+
get() {
18+
return {
19+
scheduledInstallManagers() : void { },
20+
commit() : void {
21+
throw new Error('something failed');
22+
}
23+
};
24+
}
25+
});
26+
27+
assert.throws(() => env.commit(), 'something failed'); // commit failed
28+
29+
// but a previous commit failing, does not cause a future transaction to fail to start
30+
env.begin();
31+
});

0 commit comments

Comments
 (0)