orez-lite 0.10.7 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/host.d.ts.map +1 -1
- package/dist/browser/host.js +8 -29
- package/dist/browser/host.js.map +1 -1
- package/dist/browser/types.d.ts +4 -2
- package/dist/browser/types.d.ts.map +1 -1
- package/dist/browser/types.js.map +1 -1
- package/dist/cf-do/application-sql.d.ts +24 -5
- package/dist/cf-do/application-sql.d.ts.map +1 -1
- package/dist/cf-do/application-sql.js +51 -43
- package/dist/cf-do/application-sql.js.map +1 -1
- package/dist/cf-do/worker.d.ts +74 -14
- package/dist/cf-do/worker.d.ts.map +1 -1
- package/dist/cf-do/worker.js +195 -92
- package/dist/cf-do/worker.js.map +1 -1
- package/dist/do-sql-tracking.d.ts +17 -0
- package/dist/do-sql-tracking.d.ts.map +1 -1
- package/dist/do-sql-tracking.js +17 -0
- package/dist/do-sql-tracking.js.map +1 -1
- package/dist/realtime/host.d.ts +7 -0
- package/dist/realtime/host.d.ts.map +1 -0
- package/dist/realtime/host.js +77 -0
- package/dist/realtime/host.js.map +1 -0
- package/dist/realtime/hub.d.ts +10 -5
- package/dist/realtime/hub.d.ts.map +1 -1
- package/dist/realtime/hub.js +133 -53
- package/dist/realtime/hub.js.map +1 -1
- package/dist/realtime/index.d.ts +15 -2
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/realtime/index.js +12 -0
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime/local.d.ts +15 -0
- package/dist/realtime/local.d.ts.map +1 -0
- package/dist/realtime/local.js +63 -0
- package/dist/realtime/local.js.map +1 -0
- package/dist/realtime/manifest.d.ts +5 -1
- package/dist/realtime/manifest.d.ts.map +1 -1
- package/dist/realtime/manifest.js +1 -1
- package/dist/realtime/manifest.js.map +1 -1
- package/dist/realtime/message-port.d.ts +34 -0
- package/dist/realtime/message-port.d.ts.map +1 -0
- package/dist/realtime/message-port.js +141 -0
- package/dist/realtime/message-port.js.map +1 -0
- package/dist/realtime/producer-socket.d.ts +10 -0
- package/dist/realtime/producer-socket.d.ts.map +1 -0
- package/dist/realtime/producer-socket.js +90 -0
- package/dist/realtime/producer-socket.js.map +1 -0
- package/dist/realtime/producer.d.ts +16 -0
- package/dist/realtime/producer.d.ts.map +1 -0
- package/dist/realtime/producer.js +51 -0
- package/dist/realtime/producer.js.map +1 -0
- package/dist/realtime/protocol.d.ts +38 -2
- package/dist/realtime/protocol.d.ts.map +1 -1
- package/dist/realtime/protocol.js +34 -0
- package/dist/realtime/protocol.js.map +1 -1
- package/dist/realtime/publisher.d.ts +1 -0
- package/dist/realtime/publisher.d.ts.map +1 -1
- package/dist/realtime/publisher.js +29 -1
- package/dist/realtime/publisher.js.map +1 -1
- package/dist/realtime/socket-host.d.ts +25 -0
- package/dist/realtime/socket-host.d.ts.map +1 -0
- package/dist/realtime/socket-host.js +95 -0
- package/dist/realtime/socket-host.js.map +1 -0
- package/dist/realtime/store.d.ts +4 -4
- package/dist/realtime/store.d.ts.map +1 -1
- package/dist/realtime/store.js +0 -0
- package/dist/realtime/store.js.map +1 -1
- package/dist/realtime/writer.d.ts +17 -0
- package/dist/realtime/writer.d.ts.map +1 -0
- package/dist/realtime/writer.js +138 -0
- package/dist/realtime/writer.js.map +1 -0
- package/package.json +4 -4
package/dist/cf-do/worker.js
CHANGED
|
@@ -97,15 +97,17 @@ const APPLICATION_SQL_DISPOSE = Symbol('applicationSqlDispose');
|
|
|
97
97
|
class ApplicationSqlSessionTarget extends RpcTarget {
|
|
98
98
|
owner;
|
|
99
99
|
sessionID;
|
|
100
|
+
readOnly;
|
|
100
101
|
state = 'created';
|
|
101
102
|
changed = false;
|
|
102
103
|
mutated = false;
|
|
103
|
-
constructor(owner, sessionID) {
|
|
104
|
+
constructor(owner, sessionID, readOnly) {
|
|
104
105
|
super();
|
|
105
106
|
this.owner = owner;
|
|
106
107
|
this.sessionID = sessionID;
|
|
108
|
+
this.readOnly = readOnly;
|
|
107
109
|
}
|
|
108
|
-
|
|
110
|
+
begin() {
|
|
109
111
|
return this.owner[APPLICATION_SQL_ACQUIRE](this);
|
|
110
112
|
}
|
|
111
113
|
query(sql, params = []) {
|
|
@@ -142,7 +144,9 @@ export class ZeroDO extends DurableObject {
|
|
|
142
144
|
activeWriteMeasurements = null;
|
|
143
145
|
writeBudgetTripStatement;
|
|
144
146
|
pendingChangesSchemaReady = false;
|
|
145
|
-
|
|
147
|
+
applicationSqlWriter = null;
|
|
148
|
+
applicationSqlReaders = new Set();
|
|
149
|
+
applicationSqlQueue = [];
|
|
146
150
|
applicationSqlDidCommit(_changed, _mutated) { }
|
|
147
151
|
recordWriteBudgetRows(rows, statement) {
|
|
148
152
|
const wasTripped = this.writeBudget.status().tripped;
|
|
@@ -990,70 +994,150 @@ export class ZeroDO extends DurableObject {
|
|
|
990
994
|
}));
|
|
991
995
|
}
|
|
992
996
|
assertApplicationSqlSession(session) {
|
|
993
|
-
|
|
997
|
+
const admitted = session.readOnly
|
|
998
|
+
? this.applicationSqlReaders.has(session)
|
|
999
|
+
: this.applicationSqlWriter === session;
|
|
1000
|
+
if (session.state !== 'active' || !admitted) {
|
|
994
1001
|
throw new Error('application SQLite session is not active');
|
|
995
1002
|
}
|
|
996
1003
|
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1004
|
+
/**
|
|
1005
|
+
* Read sessions never mutate, so no lane can escalate and there is nothing to
|
|
1006
|
+
* deadlock over: a reader waits only on the writer, and the writer waits only
|
|
1007
|
+
* on the reader set draining.
|
|
1008
|
+
*/
|
|
1009
|
+
canAdmitApplicationSqlSession(session) {
|
|
1010
|
+
if (this.applicationSqlWriter)
|
|
1011
|
+
return false;
|
|
1012
|
+
return session.readOnly || this.applicationSqlReaders.size === 0;
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Admit from the head of the arrival queue and stop at the first waiter that
|
|
1016
|
+
* cannot run yet.
|
|
1017
|
+
*
|
|
1018
|
+
* The stop is what makes this fair. Scanning past a blocked writer to admit
|
|
1019
|
+
* younger readers would let a steady read load hold the turn away from it
|
|
1020
|
+
* indefinitely, which is the starvation the competitive `begin()` poll this
|
|
1021
|
+
* replaces produced in production: callers raced a 25 ms timer for one
|
|
1022
|
+
* ownership flag, so admission order was decided by poll phase, and sessions
|
|
1023
|
+
* that had arrived ten seconds earlier watched later ones complete.
|
|
1024
|
+
*/
|
|
1025
|
+
pumpApplicationSqlQueue() {
|
|
1026
|
+
while (this.applicationSqlQueue.length > 0) {
|
|
1027
|
+
const waiter = this.applicationSqlQueue[0];
|
|
1028
|
+
if (waiter.session.state !== 'waiting') {
|
|
1029
|
+
this.applicationSqlQueue.shift();
|
|
1030
|
+
clearTimeout(waiter.timer);
|
|
1031
|
+
continue;
|
|
1032
|
+
}
|
|
1033
|
+
if (!this.canAdmitApplicationSqlSession(waiter.session))
|
|
1034
|
+
return;
|
|
1035
|
+
this.applicationSqlQueue.shift();
|
|
1036
|
+
clearTimeout(waiter.timer);
|
|
1037
|
+
waiter.session.state = 'active';
|
|
1038
|
+
if (waiter.session.readOnly)
|
|
1039
|
+
this.applicationSqlReaders.add(waiter.session);
|
|
1040
|
+
else
|
|
1041
|
+
this.applicationSqlWriter = waiter.session;
|
|
1042
|
+
waiter.admit();
|
|
1000
1043
|
}
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Join the arrival queue and resolve when this session owns its turn.
|
|
1047
|
+
*
|
|
1048
|
+
* A waiting session holds one queue entry and one timer, and nothing else:
|
|
1049
|
+
* cancellation, rollback and RPC stub disposal all route through
|
|
1050
|
+
* `releaseApplicationSqlTurn`, which drops the entry and re-pumps. The
|
|
1051
|
+
* deadline bounds a queue entry whose caller neither cancels nor disposes,
|
|
1052
|
+
* and reports the wait as an error instead of hanging the request.
|
|
1053
|
+
*/
|
|
1054
|
+
[APPLICATION_SQL_ACQUIRE](session) {
|
|
1001
1055
|
if (session.state !== 'created') {
|
|
1002
|
-
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1056
|
+
return Promise.reject(new Error('application SQLite session cannot begin again'));
|
|
1057
|
+
}
|
|
1058
|
+
session.state = 'waiting';
|
|
1059
|
+
const admission = new Promise((resolve, reject) => {
|
|
1060
|
+
const waiter = {
|
|
1061
|
+
session,
|
|
1062
|
+
admit: resolve,
|
|
1063
|
+
reject,
|
|
1064
|
+
timer: setTimeout(() => {
|
|
1065
|
+
const index = this.applicationSqlQueue.indexOf(waiter);
|
|
1066
|
+
if (index < 0)
|
|
1067
|
+
return;
|
|
1068
|
+
this.applicationSqlQueue.splice(index, 1);
|
|
1069
|
+
session.state = 'closed';
|
|
1070
|
+
reject(new Error('timed out acquiring the application SQLite session'));
|
|
1071
|
+
}, APPLICATION_SQL_TURN_WAIT_MS),
|
|
1072
|
+
};
|
|
1073
|
+
this.applicationSqlQueue.push(waiter);
|
|
1074
|
+
this.pumpApplicationSqlQueue();
|
|
1075
|
+
});
|
|
1076
|
+
return admission;
|
|
1009
1077
|
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Close a session in any state and hand the turn to the next arrival.
|
|
1080
|
+
*
|
|
1081
|
+
* A session that is still queued has never touched SQLite, so dropping its
|
|
1082
|
+
* queue entry is the whole of its cleanup.
|
|
1083
|
+
*/
|
|
1010
1084
|
releaseApplicationSqlTurn(session) {
|
|
1085
|
+
if (session.state === 'closed')
|
|
1086
|
+
return;
|
|
1087
|
+
if (session.state === 'created') {
|
|
1088
|
+
session.state = 'closed';
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
if (session.state === 'waiting') {
|
|
1092
|
+
const index = this.applicationSqlQueue.findIndex((waiter) => waiter.session === session);
|
|
1093
|
+
if (index >= 0) {
|
|
1094
|
+
const [waiter] = this.applicationSqlQueue.splice(index, 1);
|
|
1095
|
+
clearTimeout(waiter.timer);
|
|
1096
|
+
}
|
|
1097
|
+
// The in-flight `begin()` is left unsettled on purpose. Only this
|
|
1098
|
+
// session's own caller can close it while it waits, and by then that
|
|
1099
|
+
// caller has stopped awaiting admission and is on its way to disposing
|
|
1100
|
+
// the stub, which cancels the call. Rejecting instead delivers an error
|
|
1101
|
+
// nobody is listening for, and workerd reports every one of those as an
|
|
1102
|
+
// uncaught error — measured, one per cancellation.
|
|
1103
|
+
session.state = 'closed';
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1011
1106
|
this.assertApplicationSqlSession(session);
|
|
1012
1107
|
session.state = 'closed';
|
|
1013
|
-
|
|
1108
|
+
if (session.readOnly)
|
|
1109
|
+
this.applicationSqlReaders.delete(session);
|
|
1110
|
+
else
|
|
1111
|
+
this.applicationSqlWriter = null;
|
|
1112
|
+
this.pumpApplicationSqlQueue();
|
|
1014
1113
|
}
|
|
1015
1114
|
async withApplicationSqlTurn(work, signal) {
|
|
1016
|
-
const session = await this.applicationSqlSession(crypto.randomUUID()
|
|
1115
|
+
const session = await this.applicationSqlSession(crypto.randomUUID(), {
|
|
1116
|
+
readOnly: true,
|
|
1117
|
+
});
|
|
1017
1118
|
const dispose = () => session[Symbol.dispose]();
|
|
1018
1119
|
signal?.addEventListener('abort', dispose, { once: true });
|
|
1019
1120
|
try {
|
|
1020
|
-
|
|
1021
|
-
if (signal?.aborted)
|
|
1022
|
-
throw new Error('application SQLite request was canceled');
|
|
1023
|
-
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
1024
|
-
}
|
|
1121
|
+
await session.begin();
|
|
1025
1122
|
return await work();
|
|
1026
1123
|
}
|
|
1027
1124
|
finally {
|
|
1028
1125
|
signal?.removeEventListener('abort', dispose);
|
|
1029
|
-
|
|
1030
|
-
this.releaseApplicationSqlTurn(session);
|
|
1031
|
-
else if (session.state !== 'closed')
|
|
1032
|
-
dispose();
|
|
1126
|
+
dispose();
|
|
1033
1127
|
}
|
|
1034
1128
|
}
|
|
1035
1129
|
/**
|
|
1036
1130
|
* drive one application SQLite session from INSIDE this durable object.
|
|
1037
1131
|
*
|
|
1038
1132
|
* identical to the client-side session helper in application-sql.ts — same
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1041
|
-
*
|
|
1133
|
+
* admission, same per-statement journal, same commit/rollback — except every
|
|
1134
|
+
* call is local instead of an RPC. the caller must already be running in this
|
|
1135
|
+
* object.
|
|
1042
1136
|
*/
|
|
1043
|
-
async withLocalApplicationSqlSession(work) {
|
|
1044
|
-
const session = await this.applicationSqlSession(crypto.randomUUID());
|
|
1137
|
+
async withLocalApplicationSqlSession(readOnly, work) {
|
|
1138
|
+
const session = await this.applicationSqlSession(crypto.randomUUID(), { readOnly });
|
|
1045
1139
|
try {
|
|
1046
|
-
|
|
1047
|
-
// stops polling and frees the turn; a local caller has no signal to
|
|
1048
|
-
// observe, so an unbounded loop would spin for the life of the object
|
|
1049
|
-
// every time somebody abandoned a request mid-reconcile.
|
|
1050
|
-
const deadline = Date.now() + APPLICATION_SQL_TURN_WAIT_MS;
|
|
1051
|
-
while (!(await session.begin())) {
|
|
1052
|
-
if (Date.now() >= deadline) {
|
|
1053
|
-
throw new Error('timed out acquiring the application SQLite session');
|
|
1054
|
-
}
|
|
1055
|
-
await scheduler.wait(25);
|
|
1056
|
-
}
|
|
1140
|
+
await session.begin();
|
|
1057
1141
|
const value = await work(session);
|
|
1058
1142
|
await session.commit();
|
|
1059
1143
|
return value;
|
|
@@ -1079,20 +1163,22 @@ export class ZeroDO extends DurableObject {
|
|
|
1079
1163
|
* the transport is.
|
|
1080
1164
|
*/
|
|
1081
1165
|
applicationSqlLocalClient(namespace) {
|
|
1082
|
-
const run = (work) => this.withLocalApplicationSqlSession(work);
|
|
1166
|
+
const run = (readOnly, work) => this.withLocalApplicationSqlSession(readOnly, work);
|
|
1167
|
+
const transaction = (readOnly, compileQuery, work, queryBudget) => run(readOnly, async (session) => work({
|
|
1168
|
+
exec: (sql, params = [], metadata) => session.exec(sql, params, metadata),
|
|
1169
|
+
query: (sql, params = []) => session.query(sql, params),
|
|
1170
|
+
registerTables: (tables) => session.registerTables(tables),
|
|
1171
|
+
async queryAst(ast, format, queryName) {
|
|
1172
|
+
return session.queryPlan(await compileQuery(ast, format), queryName, queryBudget);
|
|
1173
|
+
},
|
|
1174
|
+
}));
|
|
1083
1175
|
return {
|
|
1084
1176
|
namespace,
|
|
1085
|
-
query: (sql, params = []) => run((session) => session.query(sql, params)),
|
|
1086
|
-
exec: (sql, params = [], metadata) => run((session) => session.exec(sql, params, metadata)),
|
|
1087
|
-
registerTables: (tables) => run((session) => session.registerTables(tables)),
|
|
1088
|
-
transaction: (compileQuery, work, queryBudget) =>
|
|
1089
|
-
|
|
1090
|
-
query: (sql, params = []) => session.query(sql, params),
|
|
1091
|
-
registerTables: (tables) => session.registerTables(tables),
|
|
1092
|
-
async queryAst(ast, format, queryName) {
|
|
1093
|
-
return session.queryPlan(await compileQuery(ast, format), queryName, queryBudget);
|
|
1094
|
-
},
|
|
1095
|
-
})),
|
|
1177
|
+
query: (sql, params = []) => run(true, (session) => session.query(sql, params)),
|
|
1178
|
+
exec: (sql, params = [], metadata) => run(false, (session) => session.exec(sql, params, metadata)),
|
|
1179
|
+
registerTables: (tables) => run(false, (session) => session.registerTables(tables)),
|
|
1180
|
+
transaction: (compileQuery, work, queryBudget) => transaction(false, compileQuery, work, queryBudget),
|
|
1181
|
+
readTransaction: (compileQuery, work, queryBudget) => transaction(true, compileQuery, work, queryBudget),
|
|
1096
1182
|
};
|
|
1097
1183
|
}
|
|
1098
1184
|
registerApplicationSqlTables(tables) {
|
|
@@ -1106,14 +1192,25 @@ export class ZeroDO extends DurableObject {
|
|
|
1106
1192
|
}
|
|
1107
1193
|
/**
|
|
1108
1194
|
* private durable object RPC surface for the application SQLite client. the
|
|
1109
|
-
* disposable target exists before
|
|
1110
|
-
*
|
|
1111
|
-
*
|
|
1195
|
+
* disposable target exists before admission, so a queued caller can cancel by
|
|
1196
|
+
* disposing it and an active one rolls its transaction back. this method is
|
|
1197
|
+
* intentionally absent from fetch().
|
|
1112
1198
|
*/
|
|
1113
|
-
async applicationSqlSession(sessionID) {
|
|
1199
|
+
async applicationSqlSession(sessionID, options = {}) {
|
|
1114
1200
|
if (!sessionID)
|
|
1115
1201
|
throw new TypeError('application SQLite session id is required');
|
|
1116
|
-
return new ApplicationSqlSessionTarget(this, sessionID);
|
|
1202
|
+
return new ApplicationSqlSessionTarget(this, sessionID, options.readOnly === true);
|
|
1203
|
+
}
|
|
1204
|
+
/**
|
|
1205
|
+
* Run one read statement end to end in a single round trip.
|
|
1206
|
+
*
|
|
1207
|
+
* A single statement is already atomic, so a session that exists only to
|
|
1208
|
+
* carry it costs four sequential RPCs (open, admit, run, commit) for one
|
|
1209
|
+
* SELECT — the shape every authenticated read on the sync path pays. This
|
|
1210
|
+
* opens, admits, runs and closes the same read session locally instead.
|
|
1211
|
+
*/
|
|
1212
|
+
async applicationSqlQuery(sql, params = []) {
|
|
1213
|
+
return this.withLocalApplicationSqlSession(true, (session) => session.query(sql, params));
|
|
1117
1214
|
}
|
|
1118
1215
|
prepareApplicationSqlMutation(sessionID, sql) {
|
|
1119
1216
|
if (!isSqlMutation(sql))
|
|
@@ -1132,8 +1229,20 @@ export class ZeroDO extends DurableObject {
|
|
|
1132
1229
|
beginTxJournal(this.sql, sessionID, 'application');
|
|
1133
1230
|
return true;
|
|
1134
1231
|
}
|
|
1135
|
-
|
|
1232
|
+
/**
|
|
1233
|
+
* A read session declared its lane before it was admitted, and readers run
|
|
1234
|
+
* alongside each other on the strength of that declaration. Escalating one
|
|
1235
|
+
* mid-session would strand every other reader on a state that is no longer
|
|
1236
|
+
* committed, so a mutation here is an error rather than an upgrade.
|
|
1237
|
+
*/
|
|
1238
|
+
assertApplicationSqlStatement(session, sql) {
|
|
1136
1239
|
this.assertApplicationSqlSession(session);
|
|
1240
|
+
if (session.readOnly && classifySql(sql).mutation) {
|
|
1241
|
+
throw new Error('read-only application SQLite session cannot execute a mutation');
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
async [APPLICATION_SQL_QUERY](session, sql, params = []) {
|
|
1245
|
+
this.assertApplicationSqlStatement(session, sql);
|
|
1137
1246
|
return this.atomically(() => {
|
|
1138
1247
|
if (this.prepareApplicationSqlMutation(session.sessionID, sql)) {
|
|
1139
1248
|
session.mutated = true;
|
|
@@ -1142,7 +1251,7 @@ export class ZeroDO extends DurableObject {
|
|
|
1142
1251
|
});
|
|
1143
1252
|
}
|
|
1144
1253
|
async [APPLICATION_SQL_EXEC](session, sql, params = [], metadata) {
|
|
1145
|
-
this.
|
|
1254
|
+
this.assertApplicationSqlStatement(session, sql);
|
|
1146
1255
|
return this.atomically(() => {
|
|
1147
1256
|
if (this.prepareApplicationSqlMutation(session.sessionID, sql)) {
|
|
1148
1257
|
session.mutated = true;
|
|
@@ -1155,10 +1264,16 @@ export class ZeroDO extends DurableObject {
|
|
|
1155
1264
|
}
|
|
1156
1265
|
async [APPLICATION_SQL_QUERY_PLAN](session, plan, queryName, queryBudget) {
|
|
1157
1266
|
this.assertApplicationSqlSession(session);
|
|
1158
|
-
return this.atomically(() => executeTransactionQueryPlan(plan, (sql, params) =>
|
|
1267
|
+
return this.atomically(() => executeTransactionQueryPlan(plan, (sql, params) => {
|
|
1268
|
+
this.assertApplicationSqlStatement(session, sql);
|
|
1269
|
+
return this.executeSQL(sql, params, undefined, session.sessionID).rows;
|
|
1270
|
+
}, { queryName, budget: queryBudget }));
|
|
1159
1271
|
}
|
|
1160
1272
|
async [APPLICATION_SQL_REGISTER_TABLES](session, tables) {
|
|
1161
1273
|
this.assertApplicationSqlSession(session);
|
|
1274
|
+
if (session.readOnly) {
|
|
1275
|
+
throw new Error('read-only application SQLite session cannot register tables');
|
|
1276
|
+
}
|
|
1162
1277
|
await this.atomically(() => this.registerApplicationSqlTables(tables));
|
|
1163
1278
|
}
|
|
1164
1279
|
async [APPLICATION_SQL_COMMIT](session) {
|
|
@@ -1176,14 +1291,16 @@ export class ZeroDO extends DurableObject {
|
|
|
1176
1291
|
}
|
|
1177
1292
|
this.applicationSqlDidCommit(session.changed, session.mutated);
|
|
1178
1293
|
}
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1294
|
+
/**
|
|
1295
|
+
* Undo whatever this session wrote and hand its turn on.
|
|
1296
|
+
*
|
|
1297
|
+
* Rollback, cancellation and RPC stub disposal are the same operation: a
|
|
1298
|
+
* session that never reached SQLite only has to leave the queue, and one that
|
|
1299
|
+
* did has to replay its row images before releasing.
|
|
1300
|
+
*/
|
|
1301
|
+
closeApplicationSqlSession(session) {
|
|
1302
|
+
if (session.state === 'active' && session.mutated) {
|
|
1303
|
+
try {
|
|
1187
1304
|
this.rollbackAtomicallyWithoutForeignKeys(() => {
|
|
1188
1305
|
this.rollbackPendingTrackedChanges(session.sessionID);
|
|
1189
1306
|
rollbackTxJournal(this.sql, session.sessionID);
|
|
@@ -1191,32 +1308,18 @@ export class ZeroDO extends DurableObject {
|
|
|
1191
1308
|
});
|
|
1192
1309
|
this.invalidateSchemaCaches();
|
|
1193
1310
|
}
|
|
1311
|
+
finally {
|
|
1312
|
+
this.releaseApplicationSqlTurn(session);
|
|
1313
|
+
}
|
|
1314
|
+
return;
|
|
1194
1315
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1316
|
+
this.releaseApplicationSqlTurn(session);
|
|
1317
|
+
}
|
|
1318
|
+
async [APPLICATION_SQL_ROLLBACK](session) {
|
|
1319
|
+
this.closeApplicationSqlSession(session);
|
|
1198
1320
|
}
|
|
1199
1321
|
[APPLICATION_SQL_DISPOSE](session) {
|
|
1200
|
-
|
|
1201
|
-
return;
|
|
1202
|
-
if (session.state === 'created') {
|
|
1203
|
-
session.state = 'closed';
|
|
1204
|
-
return;
|
|
1205
|
-
}
|
|
1206
|
-
this.assertApplicationSqlSession(session);
|
|
1207
|
-
try {
|
|
1208
|
-
if (session.mutated) {
|
|
1209
|
-
this.rollbackAtomicallyWithoutForeignKeys(() => {
|
|
1210
|
-
this.rollbackPendingTrackedChanges(session.sessionID);
|
|
1211
|
-
rollbackTxJournal(this.sql, session.sessionID);
|
|
1212
|
-
this.deletePendingTrackedChanges(session.sessionID);
|
|
1213
|
-
});
|
|
1214
|
-
this.invalidateSchemaCaches();
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
finally {
|
|
1218
|
-
this.releaseApplicationSqlTurn(session);
|
|
1219
|
-
}
|
|
1322
|
+
this.closeApplicationSqlSession(session);
|
|
1220
1323
|
}
|
|
1221
1324
|
atomicallySync(work) {
|
|
1222
1325
|
try {
|