@prisma/client-engine-runtime 7.5.0-dev.12 → 7.5.0-dev.14
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/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +143 -11
- package/dist/index.mjs +143 -11
- package/dist/transaction-manager/transaction.d.ts +1 -0
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -2087,13 +2087,42 @@ var TransactionManager = class {
|
|
|
2087
2087
|
);
|
|
2088
2088
|
}
|
|
2089
2089
|
async #startTransactionImpl(options) {
|
|
2090
|
+
if (options.newTxId) {
|
|
2091
|
+
return await this.#withActiveTransactionLock(options.newTxId, "start", async (existing) => {
|
|
2092
|
+
if (existing.status !== "running") {
|
|
2093
|
+
throw new TransactionInternalConsistencyError(
|
|
2094
|
+
`Transaction in invalid state ${existing.status} when starting a nested transaction.`
|
|
2095
|
+
);
|
|
2096
|
+
}
|
|
2097
|
+
if (!existing.transaction) {
|
|
2098
|
+
throw new TransactionInternalConsistencyError(
|
|
2099
|
+
`Transaction missing underlying driver transaction when starting a nested transaction.`
|
|
2100
|
+
);
|
|
2101
|
+
}
|
|
2102
|
+
existing.depth += 1;
|
|
2103
|
+
const savepointName = this.#nextSavepointName(existing);
|
|
2104
|
+
existing.savepoints.push(savepointName);
|
|
2105
|
+
try {
|
|
2106
|
+
await this.#requiredCreateSavepoint(existing.transaction)(savepointName);
|
|
2107
|
+
} catch (e) {
|
|
2108
|
+
existing.depth -= 1;
|
|
2109
|
+
existing.savepoints.pop();
|
|
2110
|
+
throw e;
|
|
2111
|
+
}
|
|
2112
|
+
return { id: existing.id };
|
|
2113
|
+
});
|
|
2114
|
+
}
|
|
2090
2115
|
const transaction = {
|
|
2091
2116
|
id: await randomUUID(),
|
|
2092
2117
|
status: "waiting",
|
|
2093
2118
|
timer: void 0,
|
|
2094
2119
|
timeout: options.timeout,
|
|
2095
2120
|
startedAt: Date.now(),
|
|
2096
|
-
transaction: void 0
|
|
2121
|
+
transaction: void 0,
|
|
2122
|
+
operationQueue: Promise.resolve(),
|
|
2123
|
+
depth: 1,
|
|
2124
|
+
savepoints: [],
|
|
2125
|
+
savepointCounter: 0
|
|
2097
2126
|
};
|
|
2098
2127
|
const abortController = new AbortController();
|
|
2099
2128
|
const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
|
|
@@ -2127,14 +2156,49 @@ var TransactionManager = class {
|
|
|
2127
2156
|
}
|
|
2128
2157
|
async commitTransaction(transactionId) {
|
|
2129
2158
|
return await this.tracingHelper.runInChildSpan("commit_transaction", async () => {
|
|
2130
|
-
|
|
2131
|
-
|
|
2159
|
+
await this.#withActiveTransactionLock(transactionId, "commit", async (txw) => {
|
|
2160
|
+
if (txw.depth > 1) {
|
|
2161
|
+
if (!txw.transaction) throw new TransactionNotFoundError();
|
|
2162
|
+
const savepointName = txw.savepoints.at(-1);
|
|
2163
|
+
if (!savepointName) {
|
|
2164
|
+
throw new TransactionInternalConsistencyError(
|
|
2165
|
+
`Missing savepoint for nested commit. Depth: ${txw.depth}, transactionId: ${txw.id}`
|
|
2166
|
+
);
|
|
2167
|
+
}
|
|
2168
|
+
try {
|
|
2169
|
+
await this.#releaseSavepoint(txw.transaction, savepointName);
|
|
2170
|
+
} finally {
|
|
2171
|
+
txw.savepoints.pop();
|
|
2172
|
+
txw.depth -= 1;
|
|
2173
|
+
}
|
|
2174
|
+
return;
|
|
2175
|
+
}
|
|
2176
|
+
await this.#closeTransaction(txw, "committed");
|
|
2177
|
+
});
|
|
2132
2178
|
});
|
|
2133
2179
|
}
|
|
2134
2180
|
async rollbackTransaction(transactionId) {
|
|
2135
2181
|
return await this.tracingHelper.runInChildSpan("rollback_transaction", async () => {
|
|
2136
|
-
|
|
2137
|
-
|
|
2182
|
+
await this.#withActiveTransactionLock(transactionId, "rollback", async (txw) => {
|
|
2183
|
+
if (txw.depth > 1) {
|
|
2184
|
+
if (!txw.transaction) throw new TransactionNotFoundError();
|
|
2185
|
+
const savepointName = txw.savepoints.at(-1);
|
|
2186
|
+
if (!savepointName) {
|
|
2187
|
+
throw new TransactionInternalConsistencyError(
|
|
2188
|
+
`Missing savepoint for nested rollback. Depth: ${txw.depth}, transactionId: ${txw.id}`
|
|
2189
|
+
);
|
|
2190
|
+
}
|
|
2191
|
+
try {
|
|
2192
|
+
await this.#requiredRollbackToSavepoint(txw.transaction)(savepointName);
|
|
2193
|
+
await this.#releaseSavepoint(txw.transaction, savepointName);
|
|
2194
|
+
} finally {
|
|
2195
|
+
txw.savepoints.pop();
|
|
2196
|
+
txw.depth -= 1;
|
|
2197
|
+
}
|
|
2198
|
+
return;
|
|
2199
|
+
}
|
|
2200
|
+
await this.#closeTransaction(txw, "rolled_back");
|
|
2201
|
+
});
|
|
2138
2202
|
});
|
|
2139
2203
|
}
|
|
2140
2204
|
async getTransaction(txInfo, operation) {
|
|
@@ -2178,22 +2242,90 @@ var TransactionManager = class {
|
|
|
2178
2242
|
return transaction;
|
|
2179
2243
|
}
|
|
2180
2244
|
async cancelAllTransactions() {
|
|
2181
|
-
await Promise.allSettled(
|
|
2245
|
+
await Promise.allSettled(
|
|
2246
|
+
[...this.transactions.values()].map(
|
|
2247
|
+
(tx) => this.#runSerialized(tx, async () => {
|
|
2248
|
+
const current = this.transactions.get(tx.id);
|
|
2249
|
+
if (current) {
|
|
2250
|
+
await this.#closeTransaction(current, "rolled_back");
|
|
2251
|
+
}
|
|
2252
|
+
})
|
|
2253
|
+
)
|
|
2254
|
+
);
|
|
2255
|
+
}
|
|
2256
|
+
#nextSavepointName(transaction) {
|
|
2257
|
+
return `prisma_sp_${transaction.savepointCounter++}`;
|
|
2258
|
+
}
|
|
2259
|
+
#requiredCreateSavepoint(transaction) {
|
|
2260
|
+
if (transaction.createSavepoint) {
|
|
2261
|
+
return transaction.createSavepoint.bind(transaction);
|
|
2262
|
+
}
|
|
2263
|
+
throw new TransactionManagerError(
|
|
2264
|
+
`Nested transactions are not supported by adapter "${transaction.adapterName}" (${transaction.provider}): createSavepoint is not implemented.`
|
|
2265
|
+
);
|
|
2266
|
+
}
|
|
2267
|
+
#requiredRollbackToSavepoint(transaction) {
|
|
2268
|
+
if (transaction.rollbackToSavepoint) {
|
|
2269
|
+
return transaction.rollbackToSavepoint.bind(transaction);
|
|
2270
|
+
}
|
|
2271
|
+
throw new TransactionManagerError(
|
|
2272
|
+
`Nested transactions are not supported by adapter "${transaction.adapterName}" (${transaction.provider}): rollbackToSavepoint is not implemented.`
|
|
2273
|
+
);
|
|
2274
|
+
}
|
|
2275
|
+
async #releaseSavepoint(transaction, name) {
|
|
2276
|
+
if (transaction.releaseSavepoint) {
|
|
2277
|
+
await transaction.releaseSavepoint(name);
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
#debugTransactionAlreadyClosedOnTimeout(transactionId) {
|
|
2281
|
+
debug("Transaction already committed or rolled back when timeout happened.", transactionId);
|
|
2182
2282
|
}
|
|
2183
2283
|
#startTransactionTimeout(transactionId, timeout) {
|
|
2184
2284
|
const timeoutStartedAt = Date.now();
|
|
2185
2285
|
const timer = createTimeoutIfDefined(async () => {
|
|
2186
2286
|
debug("Transaction timed out.", { transactionId, timeoutStartedAt, timeout });
|
|
2187
2287
|
const tx = this.transactions.get(transactionId);
|
|
2188
|
-
if (tx
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2288
|
+
if (!tx) {
|
|
2289
|
+
this.#debugTransactionAlreadyClosedOnTimeout(transactionId);
|
|
2290
|
+
return;
|
|
2291
|
+
}
|
|
2292
|
+
await this.#runSerialized(tx, async () => {
|
|
2293
|
+
const current = this.transactions.get(transactionId);
|
|
2294
|
+
if (current && ["running", "waiting"].includes(current.status)) {
|
|
2295
|
+
await this.#closeTransaction(current, "timed_out");
|
|
2296
|
+
} else {
|
|
2297
|
+
this.#debugTransactionAlreadyClosedOnTimeout(transactionId);
|
|
2298
|
+
}
|
|
2299
|
+
});
|
|
2193
2300
|
}, timeout);
|
|
2194
2301
|
timer?.unref?.();
|
|
2195
2302
|
return timer;
|
|
2196
2303
|
}
|
|
2304
|
+
// Any operation that mutates or closes a transaction must run through this lock so
|
|
2305
|
+
// status/savepoint/depth checks and updates happen against a stable view of state.
|
|
2306
|
+
async #withActiveTransactionLock(transactionId, operation, callback) {
|
|
2307
|
+
const tx = this.#getActiveOrClosingTransaction(transactionId, operation);
|
|
2308
|
+
return await this.#runSerialized(tx, async () => {
|
|
2309
|
+
const current = this.#getActiveOrClosingTransaction(transactionId, operation);
|
|
2310
|
+
return await callback(current);
|
|
2311
|
+
});
|
|
2312
|
+
}
|
|
2313
|
+
// Serializes operations per transaction id to prevent interleaving across awaits.
|
|
2314
|
+
// This avoids races where one operation mutates savepoint/depth state while another
|
|
2315
|
+
// operation is suspended, which could otherwise corrupt cleanup logic.
|
|
2316
|
+
async #runSerialized(tx, callback) {
|
|
2317
|
+
const previousOperation = tx.operationQueue;
|
|
2318
|
+
let releaseOperationLock;
|
|
2319
|
+
tx.operationQueue = new Promise((resolve) => {
|
|
2320
|
+
releaseOperationLock = resolve;
|
|
2321
|
+
});
|
|
2322
|
+
await previousOperation;
|
|
2323
|
+
try {
|
|
2324
|
+
return await callback();
|
|
2325
|
+
} finally {
|
|
2326
|
+
releaseOperationLock();
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2197
2329
|
async #closeTransaction(tx, status) {
|
|
2198
2330
|
const createClosingPromise = async () => {
|
|
2199
2331
|
debug("Closing transaction.", { transactionId: tx.id, status });
|
package/dist/index.mjs
CHANGED
|
@@ -2036,13 +2036,42 @@ var TransactionManager = class {
|
|
|
2036
2036
|
);
|
|
2037
2037
|
}
|
|
2038
2038
|
async #startTransactionImpl(options) {
|
|
2039
|
+
if (options.newTxId) {
|
|
2040
|
+
return await this.#withActiveTransactionLock(options.newTxId, "start", async (existing) => {
|
|
2041
|
+
if (existing.status !== "running") {
|
|
2042
|
+
throw new TransactionInternalConsistencyError(
|
|
2043
|
+
`Transaction in invalid state ${existing.status} when starting a nested transaction.`
|
|
2044
|
+
);
|
|
2045
|
+
}
|
|
2046
|
+
if (!existing.transaction) {
|
|
2047
|
+
throw new TransactionInternalConsistencyError(
|
|
2048
|
+
`Transaction missing underlying driver transaction when starting a nested transaction.`
|
|
2049
|
+
);
|
|
2050
|
+
}
|
|
2051
|
+
existing.depth += 1;
|
|
2052
|
+
const savepointName = this.#nextSavepointName(existing);
|
|
2053
|
+
existing.savepoints.push(savepointName);
|
|
2054
|
+
try {
|
|
2055
|
+
await this.#requiredCreateSavepoint(existing.transaction)(savepointName);
|
|
2056
|
+
} catch (e) {
|
|
2057
|
+
existing.depth -= 1;
|
|
2058
|
+
existing.savepoints.pop();
|
|
2059
|
+
throw e;
|
|
2060
|
+
}
|
|
2061
|
+
return { id: existing.id };
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2039
2064
|
const transaction = {
|
|
2040
2065
|
id: await randomUUID(),
|
|
2041
2066
|
status: "waiting",
|
|
2042
2067
|
timer: void 0,
|
|
2043
2068
|
timeout: options.timeout,
|
|
2044
2069
|
startedAt: Date.now(),
|
|
2045
|
-
transaction: void 0
|
|
2070
|
+
transaction: void 0,
|
|
2071
|
+
operationQueue: Promise.resolve(),
|
|
2072
|
+
depth: 1,
|
|
2073
|
+
savepoints: [],
|
|
2074
|
+
savepointCounter: 0
|
|
2046
2075
|
};
|
|
2047
2076
|
const abortController = new AbortController();
|
|
2048
2077
|
const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
|
|
@@ -2076,14 +2105,49 @@ var TransactionManager = class {
|
|
|
2076
2105
|
}
|
|
2077
2106
|
async commitTransaction(transactionId) {
|
|
2078
2107
|
return await this.tracingHelper.runInChildSpan("commit_transaction", async () => {
|
|
2079
|
-
|
|
2080
|
-
|
|
2108
|
+
await this.#withActiveTransactionLock(transactionId, "commit", async (txw) => {
|
|
2109
|
+
if (txw.depth > 1) {
|
|
2110
|
+
if (!txw.transaction) throw new TransactionNotFoundError();
|
|
2111
|
+
const savepointName = txw.savepoints.at(-1);
|
|
2112
|
+
if (!savepointName) {
|
|
2113
|
+
throw new TransactionInternalConsistencyError(
|
|
2114
|
+
`Missing savepoint for nested commit. Depth: ${txw.depth}, transactionId: ${txw.id}`
|
|
2115
|
+
);
|
|
2116
|
+
}
|
|
2117
|
+
try {
|
|
2118
|
+
await this.#releaseSavepoint(txw.transaction, savepointName);
|
|
2119
|
+
} finally {
|
|
2120
|
+
txw.savepoints.pop();
|
|
2121
|
+
txw.depth -= 1;
|
|
2122
|
+
}
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
await this.#closeTransaction(txw, "committed");
|
|
2126
|
+
});
|
|
2081
2127
|
});
|
|
2082
2128
|
}
|
|
2083
2129
|
async rollbackTransaction(transactionId) {
|
|
2084
2130
|
return await this.tracingHelper.runInChildSpan("rollback_transaction", async () => {
|
|
2085
|
-
|
|
2086
|
-
|
|
2131
|
+
await this.#withActiveTransactionLock(transactionId, "rollback", async (txw) => {
|
|
2132
|
+
if (txw.depth > 1) {
|
|
2133
|
+
if (!txw.transaction) throw new TransactionNotFoundError();
|
|
2134
|
+
const savepointName = txw.savepoints.at(-1);
|
|
2135
|
+
if (!savepointName) {
|
|
2136
|
+
throw new TransactionInternalConsistencyError(
|
|
2137
|
+
`Missing savepoint for nested rollback. Depth: ${txw.depth}, transactionId: ${txw.id}`
|
|
2138
|
+
);
|
|
2139
|
+
}
|
|
2140
|
+
try {
|
|
2141
|
+
await this.#requiredRollbackToSavepoint(txw.transaction)(savepointName);
|
|
2142
|
+
await this.#releaseSavepoint(txw.transaction, savepointName);
|
|
2143
|
+
} finally {
|
|
2144
|
+
txw.savepoints.pop();
|
|
2145
|
+
txw.depth -= 1;
|
|
2146
|
+
}
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
await this.#closeTransaction(txw, "rolled_back");
|
|
2150
|
+
});
|
|
2087
2151
|
});
|
|
2088
2152
|
}
|
|
2089
2153
|
async getTransaction(txInfo, operation) {
|
|
@@ -2127,22 +2191,90 @@ var TransactionManager = class {
|
|
|
2127
2191
|
return transaction;
|
|
2128
2192
|
}
|
|
2129
2193
|
async cancelAllTransactions() {
|
|
2130
|
-
await Promise.allSettled(
|
|
2194
|
+
await Promise.allSettled(
|
|
2195
|
+
[...this.transactions.values()].map(
|
|
2196
|
+
(tx) => this.#runSerialized(tx, async () => {
|
|
2197
|
+
const current = this.transactions.get(tx.id);
|
|
2198
|
+
if (current) {
|
|
2199
|
+
await this.#closeTransaction(current, "rolled_back");
|
|
2200
|
+
}
|
|
2201
|
+
})
|
|
2202
|
+
)
|
|
2203
|
+
);
|
|
2204
|
+
}
|
|
2205
|
+
#nextSavepointName(transaction) {
|
|
2206
|
+
return `prisma_sp_${transaction.savepointCounter++}`;
|
|
2207
|
+
}
|
|
2208
|
+
#requiredCreateSavepoint(transaction) {
|
|
2209
|
+
if (transaction.createSavepoint) {
|
|
2210
|
+
return transaction.createSavepoint.bind(transaction);
|
|
2211
|
+
}
|
|
2212
|
+
throw new TransactionManagerError(
|
|
2213
|
+
`Nested transactions are not supported by adapter "${transaction.adapterName}" (${transaction.provider}): createSavepoint is not implemented.`
|
|
2214
|
+
);
|
|
2215
|
+
}
|
|
2216
|
+
#requiredRollbackToSavepoint(transaction) {
|
|
2217
|
+
if (transaction.rollbackToSavepoint) {
|
|
2218
|
+
return transaction.rollbackToSavepoint.bind(transaction);
|
|
2219
|
+
}
|
|
2220
|
+
throw new TransactionManagerError(
|
|
2221
|
+
`Nested transactions are not supported by adapter "${transaction.adapterName}" (${transaction.provider}): rollbackToSavepoint is not implemented.`
|
|
2222
|
+
);
|
|
2223
|
+
}
|
|
2224
|
+
async #releaseSavepoint(transaction, name) {
|
|
2225
|
+
if (transaction.releaseSavepoint) {
|
|
2226
|
+
await transaction.releaseSavepoint(name);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
#debugTransactionAlreadyClosedOnTimeout(transactionId) {
|
|
2230
|
+
debug("Transaction already committed or rolled back when timeout happened.", transactionId);
|
|
2131
2231
|
}
|
|
2132
2232
|
#startTransactionTimeout(transactionId, timeout) {
|
|
2133
2233
|
const timeoutStartedAt = Date.now();
|
|
2134
2234
|
const timer = createTimeoutIfDefined(async () => {
|
|
2135
2235
|
debug("Transaction timed out.", { transactionId, timeoutStartedAt, timeout });
|
|
2136
2236
|
const tx = this.transactions.get(transactionId);
|
|
2137
|
-
if (tx
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2237
|
+
if (!tx) {
|
|
2238
|
+
this.#debugTransactionAlreadyClosedOnTimeout(transactionId);
|
|
2239
|
+
return;
|
|
2240
|
+
}
|
|
2241
|
+
await this.#runSerialized(tx, async () => {
|
|
2242
|
+
const current = this.transactions.get(transactionId);
|
|
2243
|
+
if (current && ["running", "waiting"].includes(current.status)) {
|
|
2244
|
+
await this.#closeTransaction(current, "timed_out");
|
|
2245
|
+
} else {
|
|
2246
|
+
this.#debugTransactionAlreadyClosedOnTimeout(transactionId);
|
|
2247
|
+
}
|
|
2248
|
+
});
|
|
2142
2249
|
}, timeout);
|
|
2143
2250
|
timer?.unref?.();
|
|
2144
2251
|
return timer;
|
|
2145
2252
|
}
|
|
2253
|
+
// Any operation that mutates or closes a transaction must run through this lock so
|
|
2254
|
+
// status/savepoint/depth checks and updates happen against a stable view of state.
|
|
2255
|
+
async #withActiveTransactionLock(transactionId, operation, callback) {
|
|
2256
|
+
const tx = this.#getActiveOrClosingTransaction(transactionId, operation);
|
|
2257
|
+
return await this.#runSerialized(tx, async () => {
|
|
2258
|
+
const current = this.#getActiveOrClosingTransaction(transactionId, operation);
|
|
2259
|
+
return await callback(current);
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
2262
|
+
// Serializes operations per transaction id to prevent interleaving across awaits.
|
|
2263
|
+
// This avoids races where one operation mutates savepoint/depth state while another
|
|
2264
|
+
// operation is suspended, which could otherwise corrupt cleanup logic.
|
|
2265
|
+
async #runSerialized(tx, callback) {
|
|
2266
|
+
const previousOperation = tx.operationQueue;
|
|
2267
|
+
let releaseOperationLock;
|
|
2268
|
+
tx.operationQueue = new Promise((resolve) => {
|
|
2269
|
+
releaseOperationLock = resolve;
|
|
2270
|
+
});
|
|
2271
|
+
await previousOperation;
|
|
2272
|
+
try {
|
|
2273
|
+
return await callback();
|
|
2274
|
+
} finally {
|
|
2275
|
+
releaseOperationLock();
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2146
2278
|
async #closeTransaction(tx, status) {
|
|
2147
2279
|
const createClosingPromise = async () => {
|
|
2148
2280
|
debug("Closing transaction.", { transactionId: tx.id, status });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/client-engine-runtime",
|
|
3
|
-
"version": "7.5.0-dev.
|
|
3
|
+
"version": "7.5.0-dev.14",
|
|
4
4
|
"description": "This package is intended for Prisma's internal use",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"nanoid": "5.1.5",
|
|
32
32
|
"ulid": "3.0.0",
|
|
33
33
|
"uuid": "11.1.0",
|
|
34
|
-
"@prisma/
|
|
35
|
-
"@prisma/
|
|
36
|
-
"@prisma/sqlcommenter": "7.5.0-dev.
|
|
37
|
-
"@prisma/driver-adapter-utils": "7.5.0-dev.
|
|
34
|
+
"@prisma/client-runtime-utils": "7.5.0-dev.14",
|
|
35
|
+
"@prisma/debug": "7.5.0-dev.14",
|
|
36
|
+
"@prisma/sqlcommenter": "7.5.0-dev.14",
|
|
37
|
+
"@prisma/driver-adapter-utils": "7.5.0-dev.14"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@codspeed/benchmark.js-plugin": "4.0.0",
|