@sema-agent/server 7.150.0 → 7.151.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/MIGRATION.md +185 -0
- package/USAGE.md +53 -25
- package/deploy/sema-up/README.md +7 -1
- package/deploy/sema-up/chart/Chart.yaml +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
- package/deploy/sema-up/chart/templates/server.yaml +5 -3
- package/deploy/sema-up/chart/values-full-single.yaml +3 -1
- package/deploy/sema-up/chart/values.yaml +8 -1
- package/deploy/sema-up/cluster-up.sh +1 -0
- package/deploy/sema-up/kube-up.sh +1 -1
- package/deploy/sema-up/lib/flagshape.sh +1 -1
- package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
- package/deploy/sema-up/lib/helm-values-kube.py +2 -0
- package/dist/adoption/import.js +3 -3
- package/dist/approval-ask-machine.d.ts +1 -1
- package/dist/approval-card.d.ts +2 -2
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/auth-bridge.d.ts +20 -0
- package/dist/auth-bridge.js +9 -0
- package/dist/background-session-reap.d.ts +1 -1
- package/dist/bake-runner/main.d.ts +4 -2
- package/dist/bind-host.d.ts +2 -3
- package/dist/bind-host.js +2 -4
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/engine-lease.d.ts +5 -0
- package/dist/boot/engine-lease.js +1 -0
- package/dist/boot/execution-env.d.ts +8 -14
- package/dist/boot/execution-env.js +54 -17
- package/dist/boot/execution-lane.js +32 -5
- package/dist/boot/late-binds.d.ts +8 -4
- package/dist/boot/late-binds.js +7 -1
- package/dist/boot/memory-consolidation.d.ts +3 -2
- package/dist/boot/memory-consolidation.js +6 -6
- package/dist/boot/reapers.d.ts +5 -0
- package/dist/boot/reapers.js +12 -1
- package/dist/boot/resolve-spec.d.ts +3 -3
- package/dist/boot/resolve-spec.js +31 -22
- package/dist/boot/runner-deps.d.ts +9 -2
- package/dist/boot/runner-deps.js +3 -3
- package/dist/boot/session-age-out.d.ts +36 -0
- package/dist/boot/session-age-out.js +101 -0
- package/dist/boot/session-faces.d.ts +5 -14
- package/dist/boot/session-faces.js +9 -5
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-05-execution-env.d.ts +5 -3
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +7 -4
- package/dist/boot/stage-06-runners.js +15 -6
- package/dist/boot/stage-07-capability-layer.d.ts +7 -4
- package/dist/boot/stage-07-capability-layer.js +2 -1
- package/dist/boot/stage-08-reapers.d.ts +7 -4
- package/dist/boot/stage-08-reapers.js +4 -2
- package/dist/boot/stage-09-leader.d.ts +11 -5
- package/dist/boot/stage-09-leader.js +12 -3
- package/dist/boot/stage-10-http-server.d.ts +11 -5
- package/dist/boot/stage-10-http-server.js +3 -6
- package/dist/boot/web-admin.js +3 -1
- package/dist/boot/workflow-orchestration.d.ts +7 -2
- package/dist/boot/workflow-orchestration.js +24 -7
- package/dist/bounded-rotation.d.ts +29 -0
- package/dist/bounded-rotation.js +24 -0
- package/dist/capability-facts.d.ts +22 -13
- package/dist/capability-facts.js +28 -18
- package/dist/center-credential.d.ts +25 -6
- package/dist/center-credential.js +25 -5
- package/dist/config-catalog.d.ts +26 -7
- package/dist/config-catalog.js +14 -11
- package/dist/config-invariants.d.ts +2 -1
- package/dist/config-invariants.js +4 -4
- package/dist/config-types.d.ts +10 -4
- package/dist/config.d.ts +51 -2
- package/dist/config.js +35 -24
- package/dist/deployment-shape.d.ts +9 -1
- package/dist/deployment-shape.js +2 -1
- package/dist/device-protocol.d.ts +5 -4
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.js +3 -2
- package/dist/device-ws-protocol.d.ts +63 -10
- package/dist/device-ws-protocol.js +56 -25
- package/dist/engine-identity.d.ts +19 -7
- package/dist/engine-identity.js +10 -2
- package/dist/entry-mode-clamp-notice.d.ts +2 -1
- package/dist/execution-env-refusal.d.ts +23 -0
- package/dist/execution-env-refusal.js +5 -0
- package/dist/execution-lane-caps.d.ts +3 -1
- package/dist/field-conflict.d.ts +1 -1
- package/dist/file-history-capture.d.ts +11 -4
- package/dist/file-history-capture.js +9 -6
- package/dist/file-history-disclosure.d.ts +7 -5
- package/dist/file-history-disclosure.js +7 -5
- package/dist/fleet/drain-entry.d.ts +4 -0
- package/dist/hooks/hook-runner.js +2 -2
- package/dist/host-lsp-manager.d.ts +2 -2
- package/dist/http/admission.js +17 -2
- package/dist/http/approval-sweeps.js +5 -5
- package/dist/http/checkpoint-ctx.d.ts +2 -0
- package/dist/http/checkpoint-ctx.js +1 -0
- package/dist/http/dispatch.d.ts +2 -1
- package/dist/http/dispatch.js +34 -27
- package/dist/http/durable-run-leg.js +16 -16
- package/dist/http/health-self-report.d.ts +9 -1
- package/dist/http/health-self-report.js +2 -0
- package/dist/http/owner-access.d.ts +31 -11
- package/dist/http/owner-access.js +37 -6
- package/dist/http/resume-ctx-read.js +25 -3
- package/dist/http/resume-legs.d.ts +2 -1
- package/dist/http/resume-legs.js +259 -79
- package/dist/http/route-ctx.d.ts +18 -8
- package/dist/http/route-table.d.ts +1 -1
- package/dist/http/routes/admin-memory-optout.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.js +4 -3
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/capabilities.js +8 -5
- package/dist/http/routes/fleet.js +10 -8
- package/dist/http/routes/projects.d.ts +3 -2
- package/dist/http/routes/projects.js +4 -5
- package/dist/http/routes/runs.js +102 -36
- package/dist/http/routes/session-sync.d.ts +4 -3
- package/dist/http/routes/session-sync.js +172 -77
- package/dist/http/routes/sessions-list.js +13 -7
- package/dist/http/routes/sessions.js +10 -6
- package/dist/http/routes/tasks.js +30 -16
- package/dist/http/routes/trace-usage.js +2 -2
- package/dist/http/server.d.ts +21 -27
- package/dist/http/server.js +2 -2
- package/dist/http/submit-ctx.js +5 -4
- package/dist/http/wire-types.d.ts +14 -4
- package/dist/identity-source.d.ts +20 -3
- package/dist/identity-source.js +14 -0
- package/dist/index.d.ts +4 -0
- package/dist/lane-home-probe.d.ts +3 -7
- package/dist/lane-home-probe.js +0 -1
- package/dist/leader/leader.d.ts +2 -1
- package/dist/leg-facts.d.ts +13 -5
- package/dist/leg-facts.js +2 -1
- package/dist/memory-scope.d.ts +5 -4
- package/dist/memory-scope.js +4 -4
- package/dist/memory-sync-client.d.ts +30 -2
- package/dist/memory-sync-client.js +16 -9
- package/dist/observability/err-text.d.ts +7 -0
- package/dist/observability/err-text.js +5 -0
- package/dist/observability/fail-open.d.ts +7 -3
- package/dist/observability/fail-open.js +7 -3
- package/dist/observability/metrics.js +1 -0
- package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
- package/dist/orchestration/workflow-notify-journal.js +12 -1
- package/dist/orchestration/workflow-park-decision.d.ts +70 -18
- package/dist/orchestration/workflow-park-decision.js +49 -10
- package/dist/orchestration/workflow-park-holder.d.ts +65 -0
- package/dist/orchestration/workflow-park-holder.js +98 -0
- package/dist/orchestration/workflow-record-fence.d.ts +36 -0
- package/dist/orchestration/workflow-record-fence.js +42 -0
- package/dist/owner-faces.d.ts +1 -1
- package/dist/parked-decide.d.ts +104 -53
- package/dist/parked-decide.js +153 -117
- package/dist/peer-directory.d.ts +2 -2
- package/dist/peer-inbound-face.d.ts +2 -6
- package/dist/peer-inbound-face.js +0 -3
- package/dist/permission-mode-admission.d.ts +41 -5
- package/dist/permission-mode-admission.js +29 -3
- package/dist/plugins/adoption-log-sql.d.ts +3 -1
- package/dist/plugins/adoption-log-sql.js +7 -1
- package/dist/plugins/approval-ask-store-file.d.ts +10 -2
- package/dist/plugins/approval-ask-store-file.js +8 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +6 -1
- package/dist/plugins/approval-ask-store-memory.js +28 -9
- package/dist/plugins/approval-ask-store-sql.d.ts +43 -2
- package/dist/plugins/approval-ask-store-sql.js +34 -5
- package/dist/plugins/approval-exemption-store.js +3 -0
- package/dist/plugins/approval-nonce-store.js +2 -0
- package/dist/plugins/breaker-state-sql.js +2 -0
- package/dist/plugins/caching-session-store.d.ts +9 -15
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/device-store-sql.js +6 -0
- package/dist/plugins/error-origin.d.ts +18 -0
- package/dist/plugins/error-origin.js +10 -0
- package/dist/plugins/execution-placement-sql.js +6 -6
- package/dist/plugins/image-bake-store-sql.js +6 -0
- package/dist/plugins/image-index-sql.js +4 -0
- package/dist/plugins/landed-attendants.d.ts +212 -0
- package/dist/plugins/landed-attendants.js +161 -0
- package/dist/plugins/leader-run-store-sql.js +4 -0
- package/dist/plugins/local-session-live-reference.d.ts +40 -0
- package/dist/plugins/local-session-live-reference.js +39 -0
- package/dist/plugins/local-session-store.d.ts +71 -33
- package/dist/plugins/local-session-store.js +129 -27
- package/dist/plugins/memory-engine-pg.js +4 -0
- package/dist/plugins/memory-engine-sql-apply.js +5 -2
- package/dist/plugins/memory-engine-tidb.js +4 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
- package/dist/plugins/memory-sync-store-pg.js +5 -0
- package/dist/plugins/memory-sync-store-tidb.js +5 -0
- package/dist/plugins/one-time-migrations.d.ts +57 -63
- package/dist/plugins/one-time-migrations.js +162 -90
- package/dist/plugins/org-delivery-quota-store.js +4 -1
- package/dist/plugins/outcome-ledger-sql.js +2 -0
- package/dist/plugins/permission-rule-store-sql.js +11 -4
- package/dist/plugins/pg-cost-quota.js +4 -0
- package/dist/plugins/pg-pool.js +24 -1
- package/dist/plugins/pg-rate-limiter.js +2 -0
- package/dist/plugins/posix-shell-fs.d.ts +6 -1
- package/dist/plugins/posix-shell-fs.js +4 -1
- package/dist/plugins/remote-env-adb.d.ts +19 -15
- package/dist/plugins/remote-env-adb.js +41 -15
- package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
- package/dist/plugins/remote-env-connect-seat.js +72 -0
- package/dist/plugins/remote-env-device.d.ts +22 -5
- package/dist/plugins/remote-env-device.js +106 -8
- package/dist/plugins/remote-env-e2b.d.ts +15 -6
- package/dist/plugins/remote-env-e2b.js +42 -32
- package/dist/plugins/remote-env-file-error.js +6 -2
- package/dist/plugins/remote-env-host.d.ts +17 -0
- package/dist/plugins/remote-env-host.js +30 -38
- package/dist/plugins/remote-env-k8s.d.ts +41 -39
- package/dist/plugins/remote-env-k8s.js +53 -30
- package/dist/plugins/remote-env-local-docker.d.ts +13 -8
- package/dist/plugins/remote-env-local-docker.js +34 -41
- package/dist/plugins/remote-env-ssh.d.ts +18 -12
- package/dist/plugins/remote-env-ssh.js +60 -59
- package/dist/plugins/remote-shell.d.ts +98 -1
- package/dist/plugins/remote-shell.js +218 -0
- package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
- package/dist/plugins/resume-anchor-store-sql.js +12 -5
- package/dist/plugins/retention-lane-store-sql.js +4 -0
- package/dist/plugins/retention-sql.d.ts +20 -2
- package/dist/plugins/retention-sql.js +11 -0
- package/dist/plugins/run-store-sql.d.ts +21 -2
- package/dist/plugins/run-store-sql.js +31 -7
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
- package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
- package/dist/plugins/schema-consistency.d.ts +4 -2
- package/dist/plugins/schema-consistency.js +19 -2
- package/dist/plugins/send-file-ledger.js +3 -0
- package/dist/plugins/serving-requirement.d.ts +26 -7
- package/dist/plugins/serving-requirement.js +11 -4
- package/dist/plugins/session-birth.d.ts +6 -2
- package/dist/plugins/session-capture-record-store-sql.js +2 -0
- package/dist/plugins/session-ext-table.d.ts +14 -1
- package/dist/plugins/session-ext-table.js +5 -1
- package/dist/plugins/session-row-sql.d.ts +49 -2
- package/dist/plugins/session-row-sql.js +56 -13
- package/dist/plugins/session-store-sql.d.ts +34 -18
- package/dist/plugins/session-store-sql.js +98 -17
- package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
- package/dist/plugins/shared-memory-store-sql.js +6 -2
- package/dist/plugins/sql-driver.d.ts +2 -1
- package/dist/plugins/sql-driver.js +18 -3
- package/dist/plugins/sql-errors.d.ts +11 -6
- package/dist/plugins/sql-errors.js +5 -6
- package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
- package/dist/plugins/stop-then-start-sentence.js +14 -10
- package/dist/plugins/stop-then-start.d.ts +109 -0
- package/dist/plugins/stop-then-start.js +104 -0
- package/dist/plugins/store-backend.d.ts +40 -13
- package/dist/plugins/store-backend.js +169 -27
- package/dist/plugins/store-boundary.d.ts +57 -0
- package/dist/plugins/store-boundary.js +139 -0
- package/dist/plugins/store-contracts.d.ts +17 -0
- package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
- package/dist/plugins/store-fault-sentence-m53.js +25 -0
- package/dist/plugins/store-fault.d.ts +26 -7
- package/dist/plugins/store-fault.js +18 -2
- package/dist/plugins/task-attachment-store.js +9 -0
- package/dist/plugins/task-list-store-sql.d.ts +2 -2
- package/dist/plugins/task-list-store-sql.js +10 -8
- package/dist/plugins/tidb-cost-quota.js +4 -0
- package/dist/plugins/tidb-pool.js +2 -1
- package/dist/plugins/tidb-rate-limiter.js +4 -0
- package/dist/plugins/user-input-ledger-sql.js +4 -0
- package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
- package/dist/plugins/workflow-run-store-sql.js +64 -4
- package/dist/plugins/workspace-fill.d.ts +4 -7
- package/dist/plugins/workspace-fill.js +2 -1
- package/dist/plugins/write-behind-counter.js +5 -0
- package/dist/project-context.d.ts +0 -2
- package/dist/project-context.js +4 -8
- package/dist/project-registry.d.ts +46 -0
- package/dist/project-registry.js +44 -0
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +4 -0
- package/dist/request-value-closure.js +10 -0
- package/dist/run-acceptance.d.ts +3 -2
- package/dist/run-acceptance.js +4 -6
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +37 -8
- package/dist/runs.js +53 -12
- package/dist/runtime-governance.d.ts +5 -4
- package/dist/security.d.ts +30 -32
- package/dist/security.js +41 -7
- package/dist/server-secret-env.d.ts +12 -10
- package/dist/server-secret-env.js +24 -15
- package/dist/session-bindings.d.ts +82 -0
- package/dist/session-bindings.js +18 -0
- package/dist/session-children-retire.d.ts +2 -2
- package/dist/session-children-retire.js +2 -6
- package/dist/session-deletion.d.ts +16 -1
- package/dist/session-error-wire.d.ts +3 -3
- package/dist/session-error-wire.js +3 -3
- package/dist/session-incarnation.d.ts +10 -0
- package/dist/session-incarnation.js +10 -1
- package/dist/session-kind.d.ts +57 -0
- package/dist/session-kind.js +22 -0
- package/dist/session-row.d.ts +21 -1
- package/dist/session-row.js +7 -1
- package/dist/session-sync-kernel.d.ts +24 -14
- package/dist/session-sync-kernel.js +3 -6
- package/dist/session-sync.d.ts +4 -98
- package/dist/session-sync.js +1 -71
- package/dist/session-titler.d.ts +10 -3
- package/dist/session-titler.js +19 -6
- package/dist/ssh-host-key.d.ts +5 -0
- package/dist/ssh-host-key.js +3 -0
- package/dist/stores-sql/file-history-store-sql.d.ts +52 -2
- package/dist/stores-sql/file-history-store-sql.js +108 -70
- package/dist/stores-sql/pg-session-storage.d.ts +34 -7
- package/dist/stores-sql/pg-session-storage.js +37 -13
- package/dist/stores-sql/retention-store-sql.d.ts +1 -9
- package/dist/stores-sql/retention-store-sql.js +2 -10
- package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
- package/dist/stores-sql/session-policy-store-sql.js +61 -44
- package/dist/stores-sql/session-write-hooks.d.ts +11 -0
- package/dist/stores-sql/tidb-session-store.d.ts +58 -7
- package/dist/stores-sql/tidb-session-store.js +37 -13
- package/dist/submission-exit.d.ts +3 -2
- package/dist/submission-exit.js +9 -1
- package/dist/task-cwd.d.ts +2 -2
- package/dist/task-settings.d.ts +6 -5
- package/dist/terminal.d.ts +33 -2
- package/dist/terminal.js +139 -9
- package/dist/tool-approval.d.ts +140 -6
- package/dist/tool-approval.js +165 -72
- package/dist/trace/self-minted-wire.d.ts +290 -27
- package/dist/trace/self-minted-wire.js +101 -13
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +78 -27
- package/package.json +2 -2
- package/wire-changes/server@7.151.0.json +762 -0
- package/dist/http/session-inherit-env.d.ts +0 -36
- package/dist/http/session-inherit-env.js +0 -6
|
@@ -2,25 +2,30 @@
|
|
|
2
2
|
* **起服准入**(SQL 两方言;常设)—— 「这只库要求每一只服务者有哪些能力」一张表,与本构建的能力名单比:库上记着本构建没有的能力 ⇒ 拒启,本构建不迁移、不服务。
|
|
3
3
|
*
|
|
4
4
|
* ## 律
|
|
5
|
-
* · 一行一能力:`migration_id` = 能力名(= 一次性迁移名,`replica-registration.ts` 的 {@link REPLICA_CAPABILITIES} 同一词表),`state`
|
|
6
|
-
* {@link SERVING_REQUIREMENT_STATES}:`
|
|
5
|
+
* · 一行一能力:`migration_id` = 能力名(= 一次性迁移名,`replica-registration.ts` 的 {@link REPLICA_CAPABILITIES} 同一词表),`state` 一词闭集
|
|
6
|
+
* {@link SERVING_REQUIREMENT_STATES}:`in_force` = 一只带能力 M 的构建在这只库上放行了 M,M 的不兼容写已开始或马上开始。读出词表外的词(含 7.150.0 闭集里
|
|
7
|
+
* 从无写者的 `pending`)⇒ 当作 `in_force`,拒句点名那一行与原词。
|
|
7
8
|
* · 判据 = `knows(本构建, M)`(`knowsCapability`,与停-迁-起证据读法同一只谓词);发布线不进判据(同版本串的构建可以能力不同)。
|
|
8
9
|
* · 两次读,同一判据:SQL 一次性迁移段头、取迁移锁之前读一次(锁外预读);取到迁移锁之后、第一步迁移之前在锁连接上再读一次(锁内复核)——
|
|
9
10
|
* 在本进程等锁时握着锁的那一只若写下了要求,锁内复核读得到。拒 ⇒ 本构建不迁移;库上只留本进程的登记行(段头第一步)。
|
|
10
11
|
* · 表不在(跳过了 `ensureSchema()` 的嵌入方)⇒ 拒:证不出「没有要求」不是「没有要求」。
|
|
11
|
-
* ·
|
|
12
|
+
* · 写者一只({@link recordServingRequirement}):每一条停-迁-起迁移(`stop-then-start.ts`;三类围栏同记)在守卫段放行之后、它**自己的**第一笔不兼容写之前,
|
|
13
|
+
* 在锁连接上落 `(M, in_force)`(缺席才落;已在的行 —— 含词表外的词 —— 一个字节不动)。只在还欠那一条的库上写(起过那一条的库不写)。
|
|
14
|
+
* 表空 ⇒ 准入恒过。7.150.0 起的每一只构建都读它,之后写下的要求挡得住缺这项能力的构建重启开服。
|
|
15
|
+
* · 读法一只({@link unmetServingRequirements}):准入(非空即拒)与起服拒句的升级清单(点名本构建缺的在力能力)同读,不各写一句。
|
|
12
16
|
*
|
|
13
17
|
* ## 射程(如实)
|
|
14
18
|
* 挡的是**起服者**:已在服务的副本不再读本表;准入与开服之间的停顿也不在它的射程里。早于本表那一版的构建不读本表。
|
|
15
19
|
*/
|
|
16
20
|
import { StoreBootRefusalError } from "./store-contracts.js";
|
|
17
|
-
import { type ReplicaRegistration } from "./replica-registration.js";
|
|
21
|
+
import { type ReplicaCapability, type ReplicaRegistration } from "./replica-registration.js";
|
|
18
22
|
import { type UnmetServingRequirement } from "./stop-then-start-sentence.js";
|
|
23
|
+
import type { SchemaProbeRead } from "./schema-live-columns.js";
|
|
19
24
|
import type { SqlDialect, SqlExec } from "./sql-driver.js";
|
|
20
25
|
/** 表名。 */
|
|
21
26
|
export declare const SERVING_REQUIREMENT_TABLE = "serving_requirement";
|
|
22
|
-
/** 要求行的状态词(
|
|
23
|
-
export declare const SERVING_REQUIREMENT_STATES: readonly ["
|
|
27
|
+
/** 要求行的状态词(闭集;一态 —— 本构建没有「认领了、还没写」的中间态:要求紧跟在本条第一笔不兼容写之前落)。 */
|
|
28
|
+
export declare const SERVING_REQUIREMENT_STATES: readonly ["in_force"];
|
|
24
29
|
export type ServingRequirementState = (typeof SERVING_REQUIREMENT_STATES)[number];
|
|
25
30
|
/** 拒启码(确定的拒启表态;继承 {@link StoreBootRefusalError}:开库等待窗不重试、降级臂不吞)。 */
|
|
26
31
|
export declare const SERVING_REQUIREMENT_UNMET_CODE = "config.serving_requirement_unmet";
|
|
@@ -44,6 +49,20 @@ export declare class ServingRequirementUnmetError extends StoreBootRefusalError
|
|
|
44
49
|
}
|
|
45
50
|
/** 准入读的两张表(本表与段头写的登记表)都在库里;不在 ⇒ 拒(`table_absent`),点名公开序列。 */
|
|
46
51
|
export declare function assertReplicaTablesPresent(db: SqlExec, dialect: SqlDialect, me: ReplicaRegistration): Promise<void>;
|
|
47
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* **要求的唯一读法**:库上记着、本构建(`me` 的能力名单)没有的那几行,按能力名排序。纯读;两方言同一句(无占位符,读口 = 列册对账同一只无参读口)。
|
|
54
|
+
* 读者两只:准入({@link assertServingRequirementsMet},非空即拒)与起服拒句的升级清单(`schema-consistency.ts` 的 `describeUpgradeChecklist`,点名这几项能力)。
|
|
55
|
+
*/
|
|
56
|
+
export declare function unmetServingRequirements(read: SchemaProbeRead, me: Pick<ReplicaRegistration, "capabilities">): Promise<readonly UnmetServingRequirement[]>;
|
|
57
|
+
/** 准入:库上每一行要求的能力本构建都有 ⇒ 过;否则拒(`capability_missing`,点名每一行)。读法 = {@link unmetServingRequirements}。 */
|
|
48
58
|
export declare function assertServingRequirementsMet(db: SqlExec, me: ReplicaRegistration): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* **要求的唯一写口**:一条停-迁-起迁移放行之后、它自己的第一笔不兼容写之前,在迁移段的锁连接上落 `(migrationId, in_force)`。缺席才落(MySQL 协议
|
|
61
|
+
* `ON DUPLICATE KEY UPDATE migration_id = migration_id` / PG `ON CONFLICT DO NOTHING`,与副本登记句同形):已在的行 —— 含手写的词表外词 —— 一个字节不动。
|
|
62
|
+
* 记下之后缺这项能力的构建起服即拒(准入);记下之后、那一笔写之前进程崩 ⇒ 行留着(保守:缺能力的构建拒启,带能力的构建下次起服照常续)。
|
|
63
|
+
* 读写权限 7.150.0 起已是部署前提(`docs/DEPLOY-PREREQS.md` 7.150.0 节)。`migrationId` 在型上就要在能力名单里。
|
|
64
|
+
*/
|
|
65
|
+
export declare function recordServingRequirement(db: {
|
|
66
|
+
exec(sql: string, params?: readonly unknown[]): Promise<number>;
|
|
67
|
+
}, dialect: SqlDialect, migrationId: ReplicaCapability, nowMs: number): Promise<void>;
|
|
49
68
|
//# sourceMappingURL=serving-requirement.d.ts.map
|
|
@@ -2,7 +2,7 @@ import { StoreBootRefusalError } from "./store-contracts.js";
|
|
|
2
2
|
import { REPLICA_REGISTRATION_TABLE, knowsCapability } from "./replica-registration.js";
|
|
3
3
|
import { servingRequirementUnmetSentence } from "./stop-then-start-sentence.js";
|
|
4
4
|
export const SERVING_REQUIREMENT_TABLE = "serving_requirement";
|
|
5
|
-
export const SERVING_REQUIREMENT_STATES = ["
|
|
5
|
+
export const SERVING_REQUIREMENT_STATES = ["in_force"];
|
|
6
6
|
export const SERVING_REQUIREMENT_UNMET_CODE = "config.serving_requirement_unmet";
|
|
7
7
|
export function servingRequirementDdl(dialect) {
|
|
8
8
|
return dialect === "mysql"
|
|
@@ -37,17 +37,24 @@ function stateOf(cell) {
|
|
|
37
37
|
const word = String(cell);
|
|
38
38
|
return SERVING_REQUIREMENT_STATES.includes(word) ? { state: word, word } : { state: "in_force", word };
|
|
39
39
|
}
|
|
40
|
-
export async function
|
|
41
|
-
const { rows } = await db.query(`SELECT migration_id, state FROM ${SERVING_REQUIREMENT_TABLE} ORDER BY migration_id`);
|
|
40
|
+
export async function unmetServingRequirements(read, me) {
|
|
42
41
|
const unmet = [];
|
|
43
|
-
for (const r of
|
|
42
|
+
for (const r of await read(`SELECT migration_id, state FROM ${SERVING_REQUIREMENT_TABLE} ORDER BY migration_id`)) {
|
|
44
43
|
const migration = String(r["migration_id"]);
|
|
45
44
|
if (knowsCapability(me.capabilities, migration))
|
|
46
45
|
continue;
|
|
47
46
|
const { state, word } = stateOf(r["state"]);
|
|
48
47
|
unmet.push({ migration, state, word });
|
|
49
48
|
}
|
|
49
|
+
return unmet;
|
|
50
|
+
}
|
|
51
|
+
export async function assertServingRequirementsMet(db, me) {
|
|
52
|
+
const unmet = await unmetServingRequirements(async (sql) => (await db.query(sql)).rows, me);
|
|
50
53
|
if (unmet.length > 0)
|
|
51
54
|
throw new ServingRequirementUnmetError("capability_missing", unmet, [], me.releaseLine);
|
|
52
55
|
}
|
|
56
|
+
export async function recordServingRequirement(db, dialect, migrationId, nowMs) {
|
|
57
|
+
const insert = `INSERT INTO ${SERVING_REQUIREMENT_TABLE} (migration_id, state, required_at_ms) VALUES (${dialect === "mysql" ? "?, 'in_force', ?" : "$1, 'in_force', $2"})`;
|
|
58
|
+
await db.exec(dialect === "mysql" ? `${insert} ON DUPLICATE KEY UPDATE migration_id = migration_id` : `${insert} ON CONFLICT (migration_id) DO NOTHING`, [migrationId, nowMs]);
|
|
59
|
+
}
|
|
53
60
|
//# sourceMappingURL=serving-requirement.js.map
|
|
@@ -14,10 +14,14 @@
|
|
|
14
14
|
* (TiDB 悲观事务里普通 SELECT 读的是事务开始时的快照,看不到等锁期间提交的写;两方言一律 `FOR UPDATE`)。
|
|
15
15
|
*/
|
|
16
16
|
import type { SessionTreeEntry } from "@sema-agent/core";
|
|
17
|
+
import type { SessionKind } from "../session-kind.js";
|
|
17
18
|
import type { RegisterReceipt, SessionBirth, WithdrawOutcome } from "../session-incarnation.js";
|
|
18
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* 出生回执面(会话店的窄面;`register` 的同笔写形)。`kind` = 这只会话的种类(律 `session-kind.ts`):**只在这一笔真建了新行时**写下,写在建行的同一笔里
|
|
21
|
+
* (SQL = 建行事务里的建行钩;local = 建行那一笔格写);已在的行 ⇒ 零写(种类终身不改)。缺席 = 顶层对话,逐字今形。
|
|
22
|
+
*/
|
|
19
23
|
export interface SessionBirthFace {
|
|
20
|
-
registerWithReceipt(sessionId: string, owner: string | null): Promise<RegisterReceipt>;
|
|
24
|
+
registerWithReceipt(sessionId: string, owner: string | null, kind?: SessionKind): Promise<RegisterReceipt>;
|
|
21
25
|
}
|
|
22
26
|
/** 条件撤回面(会话店的窄面;部署装配在店上,一只事务里判完、删完)。`ownTaskId` = 本次提交认领赢的那条 run(没有 ⇒ 缺)。 */
|
|
23
27
|
export interface SessionWithdrawFace {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
2
2
|
import { isDupKeyError } from "./sql-errors.js";
|
|
3
|
+
import { sealStoreClass } from "./store-boundary.js";
|
|
3
4
|
export const SESSION_CAPTURE_OPTOUT_TABLE = "session_capture_optout";
|
|
4
5
|
const UNREADABLE_RECORD_REASON = "capture opt-out record present but unreadable (kept fail-closed)";
|
|
5
6
|
export const SESSION_CAPTURE_KEY_WIDTH = 255;
|
|
@@ -81,6 +82,7 @@ export class SqlSessionCaptureRecordStore {
|
|
|
81
82
|
return out;
|
|
82
83
|
}
|
|
83
84
|
}
|
|
85
|
+
sealStoreClass(SqlSessionCaptureRecordStore, "sql-session-capture-record-store", { mark: "exit", read: "exit", list: "exit" });
|
|
84
86
|
export class TiDBSessionCaptureRecordStore extends SqlSessionCaptureRecordStore {
|
|
85
87
|
constructor(pool) {
|
|
86
88
|
super(mysqlDriver(pool), "mysql");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { StoreBootRefusalError } from "./store-contracts.js";
|
|
2
2
|
import type { SqlDialect, SqlDriver } from "./sql-driver.js";
|
|
3
|
+
import type { IndexSpec } from "./ensure-index.js";
|
|
3
4
|
/** 表名(建表句、语句模块、迁移同读)。 */
|
|
4
5
|
export declare const SESSION_EXT_TABLE = "session_ext";
|
|
5
6
|
/** 一列:名字 + 两方言定义。 */
|
|
@@ -27,8 +28,20 @@ export declare const BUMP_CLIENT_WRITES = "client_writes = client_writes + 1";
|
|
|
27
28
|
* 在删对删除门之外的一切读者与写者读作「行不在」(头读 / 列表 / 规则 L 的认领);存量库缺这一列 ⇒ 起服列册对账拒启并给 `ALTER TABLE … ADD COLUMN`。
|
|
28
29
|
*/
|
|
29
30
|
export declare const DELETING_TOKEN_COLUMN: SessionExtColumn;
|
|
30
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* **会话种类**(律 `src/session-kind.ts`):`NULL` = 顶层对话(存量行与老壳建的行恒为 NULL —— 无回填、无一次性迁移);非空 = 闭集里的一个词。
|
|
33
|
+
* 唯一写者 = 建行事务里的建行钩(`plugins/session-store-sql.ts` 的 `birth.record`,本事务刚建下的这一行);此后无写口(终身不改)。宽度 32 = 词表的余量。
|
|
34
|
+
* 存量库缺这一列 ⇒ 起服列册对账拒启并给 `ALTER TABLE … ADD COLUMN`(中央建表句生成)。
|
|
35
|
+
*/
|
|
36
|
+
export declare const SESSION_KIND_COLUMN: SessionExtColumn;
|
|
37
|
+
/** 本表的全部格(主键之外),按建表句的列序。一次性迁移 M41 逐列从 `session_meta` 搬进来的是产品格与执行放置格(计数格、在删令牌与种类不在 `session_meta` 上出现过,不搬)。 */
|
|
31
38
|
export declare const SESSION_EXT_COLUMNS: readonly SessionExtColumn[];
|
|
39
|
+
/**
|
|
40
|
+
* 本表的索引声明(两方言共用一份;MySQL 协议方言另以内联 `KEY` 随建表句到货,存量库缺谁补谁 —— `ensure-index.ts`):种类那一列给老化候选面
|
|
41
|
+
* (`listIdleOfKind`:只读带种类的行,不扫整表)。
|
|
42
|
+
*/
|
|
43
|
+
export declare const SESSION_EXT_KIND_INDEX = "idx_session_ext_kind";
|
|
44
|
+
export declare const SESSION_EXT_INDEXES: readonly IndexSpec[];
|
|
32
45
|
/** M41 从 `session_meta` 搬进本表的那一组(计数格之前的全部格)。 */
|
|
33
46
|
export declare const SESSION_EXT_MOVED_COLUMNS: readonly SessionExtColumn[];
|
|
34
47
|
/** 外键约束名(两方言同名;起服探针与迁移的后置条件按名读)。 */
|
|
@@ -22,7 +22,10 @@ const PRODUCT_COLUMNS = [
|
|
|
22
22
|
export const CLIENT_WRITES_COLUMN = { name: "client_writes", mysql: "client_writes BIGINT NOT NULL DEFAULT 0", pg: "client_writes BIGINT NOT NULL DEFAULT 0" };
|
|
23
23
|
export const BUMP_CLIENT_WRITES = "client_writes = client_writes + 1";
|
|
24
24
|
export const DELETING_TOKEN_COLUMN = { name: "deleting_token", mysql: "deleting_token VARCHAR(36) NULL", pg: `deleting_token VARCHAR(36) COLLATE "C"` };
|
|
25
|
-
export const
|
|
25
|
+
export const SESSION_KIND_COLUMN = { name: "session_kind", mysql: "session_kind VARCHAR(32) NULL", pg: `session_kind VARCHAR(32) COLLATE "C"` };
|
|
26
|
+
export const SESSION_EXT_COLUMNS = [...PRODUCT_COLUMNS, ...EXECUTION_PLACEMENT_COLUMNS, CLIENT_WRITES_COLUMN, DELETING_TOKEN_COLUMN, SESSION_KIND_COLUMN];
|
|
27
|
+
export const SESSION_EXT_KIND_INDEX = "idx_session_ext_kind";
|
|
28
|
+
export const SESSION_EXT_INDEXES = [{ table: SESSION_EXT_TABLE, name: SESSION_EXT_KIND_INDEX, columns: [SESSION_KIND_COLUMN.name] }];
|
|
26
29
|
export const SESSION_EXT_MOVED_COLUMNS = [...PRODUCT_COLUMNS, ...EXECUTION_PLACEMENT_COLUMNS];
|
|
27
30
|
export const SESSION_EXT_FOREIGN_KEY = "fk_session_ext_session";
|
|
28
31
|
export const SESSION_META_KEY_COLLATION_PROBE = "SELECT CHARACTER_SET_NAME AS cs, COLLATION_NAME AS coll FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'session_meta' AND COLUMN_NAME = 'session_id'";
|
|
@@ -43,6 +46,7 @@ export function sessionExtDdl(dialect, referenced) {
|
|
|
43
46
|
` ${key},\n` +
|
|
44
47
|
SESSION_EXT_COLUMNS.map((c) => ` ${c[dialect]},\n`).join("") +
|
|
45
48
|
" PRIMARY KEY (session_id),\n" +
|
|
49
|
+
(dialect === "mysql" ? SESSION_EXT_INDEXES.map((i) => ` KEY ${i.name} (${i.columns.join(", ")}),\n`).join("") : "") +
|
|
46
50
|
` CONSTRAINT ${SESSION_EXT_FOREIGN_KEY} FOREIGN KEY (session_id) REFERENCES session_meta (session_id) ON DELETE CASCADE\n` +
|
|
47
51
|
(dialect === "pg" ? " )" : " ) COLLATE utf8mb4_bin"));
|
|
48
52
|
}
|
|
@@ -23,9 +23,56 @@
|
|
|
23
23
|
* 之后这一行连同标题换了主 —— 是行的历史,不是越权写。
|
|
24
24
|
* 应答不在事务内读(理由见上),所以③这一窗在;不取「事务内应答」。
|
|
25
25
|
* 全局锁序:根 `session_meta` 一行 → 它的旁表行(→ 读日志 mark 时它的末条事件),不碰 `task_*`(与旁表的每个写者同序:根行先)。
|
|
26
|
+
*
|
|
27
|
+
* ## 「锁根行读住客」只有一句({@link lockSessionRootOn})
|
|
28
|
+
* 部署侧(本目录之外的 `src/stores-sql/**` 不在射程)每一个先锁根 `session_meta` 行再判 / 写的写事务都经它:行格写原语与落定段({@link lockSessionRowOn})、
|
|
29
|
+
* 执行席的写序律 ①(`execution-placement-sql.ts`)、旁表格写(`session-store-sql.ts` 的 `withLockedSessionExt`)。选择列是它们要的并集(属主 · 化身 · 委派判别位 · 叶序 · 最后活动 —— 最后一格是删除围栏的老化重判读的),
|
|
30
|
+
* 各读者按自己的读法解码同一行。
|
|
31
|
+
*
|
|
32
|
+
* ## 落定段({@link withLandedRow};律在 `landed-attendants.ts` 头注)
|
|
33
|
+
* 一只事务:{@link lockSessionRowOn}(锁根行 → 补旁表行 → 锁读格与在删令牌)→ 判官 `judgeLandedRow`(就是 `judgeSessionRowWrite` 的 `replay` 写者:行在 ∧ 非在删 ∧
|
|
34
|
+
* 非委派分区 ∧ 属主与化身整对同)→ 是 ⇒ 段体在**同一连接、同一事务**里跑各店的语句源 → 提交;不是 ⇒ 回滚、一个字节不写。死锁受害 / 仲裁输了
|
|
35
|
+
* (`SqlArbitrationLostError`:文件历史哨兵消失等)⇒ 从**段首**重来(含锁根行与判,经仓里唯一的 `retryOnDeadlock`)—— 段内不许有自己回滚重开事务的语句源。
|
|
36
|
+
*/
|
|
37
|
+
import type { SqlDialect, SqlDriver, SqlTxConn } from "./sql-driver.js";
|
|
38
|
+
import type { SessionLogMark } from "@sema-agent/core";
|
|
39
|
+
import { type SessionFace } from "../session-incarnation.js";
|
|
40
|
+
import { type LockedSessionRow, type SessionRowAnswer, type SessionRowPatch, type SessionRowWrite, type SessionRowWriteOutcome, type LandedOutcome } from "../session-row.js";
|
|
41
|
+
/** 一条连接上的行读口(本事务的语句面:SQL 文本 + 参数 → 行)—— `SqlTxConn` / mysql2 连接 / node-pg 客户端各包一行即得。 */
|
|
42
|
+
export type SessionRootRowsOn = (text: string, values: readonly unknown[]) => Promise<ReadonlyArray<Readonly<Record<string, unknown>>>>;
|
|
43
|
+
/** `SqlTxConn` 的行读口。 */
|
|
44
|
+
export declare function rootRowsOnTx(conn: Pick<SqlTxConn, "query">): SessionRootRowsOn;
|
|
45
|
+
/**
|
|
46
|
+
* **锁根行读住客 —— 唯一一句**(头注):同一连接上 `SELECT owner, incarnation, placement_kind, leaf_seq, updated_at FROM session_meta WHERE session_id = ? FOR UPDATE`。
|
|
47
|
+
* 行不在 ⇒ `undefined`(InnoDB 可重复读下锁一只不在的键取间隙锁 —— 挡住同 id 的并发登记到本事务结束,调用方随即回滚)。读者各自解码五格。
|
|
48
|
+
*/
|
|
49
|
+
export declare function lockSessionRootOn(conn: SessionRootRowsOn, dialect: SqlDialect, sessionId: string): Promise<Readonly<Record<string, unknown>> | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* 会话根行的部署格(SQL 会话规则店的构造参数,组合座 `store-backend.ts` 交入;店目录不认识根行与旁表,R8):`lockRoot` = 上面那一句(行在不在),
|
|
52
|
+
* `countClientWrite` = 客户端写计数的唯一一处(`session-withdraw-sql.ts`)。形由规则店的 `SessionRootSeat` 型在组合座上结构核对。
|
|
53
|
+
*/
|
|
54
|
+
export declare const SQL_SESSION_ROOT_SEAT: {
|
|
55
|
+
readonly lockRoot: (conn: Pick<SqlTxConn, "query">, dialect: SqlDialect, sessionId: string) => Promise<boolean>;
|
|
56
|
+
readonly countClientWrite: (conn: SqlTxConn, dialect: SqlDialect, sessionId: string) => Promise<void>;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* 写原语与落定段的**同一前缀**(头注 ①):锁根行({@link lockSessionRootOn})→ 行在 ⇒ 写序律:先补旁表行、再锁定读它的格与在删令牌(锁定读永远落在一行在的记录上 ——
|
|
60
|
+
* InnoDB 间隙锁死锁,见 `execution-placement-sql.ts` 的 readCellOn;锁定读 = 最新已提交)→ 判官吃的形;`logMark` ⇒ 同锁下读日志的 mark。行不在 ⇒ `locked: undefined`。
|
|
61
|
+
*/
|
|
62
|
+
export declare function lockSessionRowOn(conn: SqlTxConn, dialect: SqlDialect, sessionId: string, opts: {
|
|
63
|
+
readonly logMark: boolean;
|
|
64
|
+
}): Promise<{
|
|
65
|
+
readonly locked: LockedSessionRow | undefined;
|
|
66
|
+
readonly mark?: SessionLogMark;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* **落定段**(头注「落定段」):一只事务里锁根行判住客(`landed` = 提交回执交回的那一位 / identical 臂门读的那一位 / 运行腿受理时见证的那一位 / 路由门读的那一位)→
|
|
70
|
+
* 是那一位 ⇒ `body(本事务连接)` → 提交 ⇒ `{ landed: true, value }`;不是 ⇒ 回滚 ⇒ `{ landed: false }`(一个字节没写)。`body` 抛 ⇒ 回滚、原样上抛(段体自己的拒,
|
|
71
|
+
* 例:规则收紧门)。死锁受害 / 仲裁输了 / `alsoRetry` 认的错 ⇒ 从段首整段重来(重来同样重锁、重判)。
|
|
26
72
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
73
|
+
export declare function withLandedRow<T>(db: Pick<SqlDriver, "dialect" | "connect">, sessionId: string, landed: SessionFace, body: (tx: SqlTxConn) => Promise<T>, opts?: {
|
|
74
|
+
readonly alsoRetry?: (err: unknown) => boolean;
|
|
75
|
+
}): Promise<LandedOutcome<T>>;
|
|
29
76
|
/**
|
|
30
77
|
* 写原语(头注):一只事务里锁根行 → 判官 → 写 / 不写;提交 / 回滚之后经 `readAnswer`(调用方店的列表行读 + 行上的住客)另读应答行。
|
|
31
78
|
* `db` = 店自己的池包成的 SqlDriver(连接经它的初始化);`readAnswer` 只在判官答 `write` / `changed` 时被调。
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { BUMP_CLIENT_WRITES, SESSION_EXT_TABLE, ensureSessionExtRowStatement } from "./session-ext-table.js";
|
|
1
|
+
import { BUMP_CLIENT_WRITES, DELETING_TOKEN_COLUMN, SESSION_EXT_TABLE, ensureSessionExtRowStatement } from "./session-ext-table.js";
|
|
2
2
|
import { incarnationFromCell } from "../session-incarnation.js";
|
|
3
|
-
import {
|
|
3
|
+
import { retryOnDeadlock } from "./sql-errors.js";
|
|
4
|
+
import { countClientWriteOn } from "./session-withdraw-sql.js";
|
|
5
|
+
import { judgeLandedRow, judgeSessionRowWrite, settleSessionRowWrite, } from "../session-row.js";
|
|
4
6
|
function binder(dialect) {
|
|
5
7
|
const values = [];
|
|
6
8
|
return {
|
|
@@ -11,11 +13,27 @@ function binder(dialect) {
|
|
|
11
13
|
},
|
|
12
14
|
};
|
|
13
15
|
}
|
|
16
|
+
export function rootRowsOnTx(conn) {
|
|
17
|
+
return async (text, values) => (await conn.query(text, [...values])).rows;
|
|
18
|
+
}
|
|
19
|
+
export async function lockSessionRootOn(conn, dialect, sessionId) {
|
|
20
|
+
return (await conn(`SELECT owner, incarnation, placement_kind, leaf_seq, updated_at FROM session_meta WHERE session_id = ${dialect === "pg" ? "$1" : "?"} FOR UPDATE`, [sessionId]))[0];
|
|
21
|
+
}
|
|
22
|
+
export const SQL_SESSION_ROOT_SEAT = {
|
|
23
|
+
async lockRoot(conn, dialect, sessionId) {
|
|
24
|
+
return (await lockSessionRootOn(rootRowsOnTx(conn), dialect, sessionId)) !== undefined;
|
|
25
|
+
},
|
|
26
|
+
async countClientWrite(conn, dialect, sessionId) {
|
|
27
|
+
await countClientWriteOn(conn, dialect, sessionId);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
14
30
|
function lockedRowFrom(dialect, sessionId, row, ext) {
|
|
31
|
+
const token = ext?.[DELETING_TOKEN_COLUMN.name];
|
|
15
32
|
return {
|
|
16
33
|
owner: row.owner === null || row.owner === undefined ? null : String(row.owner),
|
|
17
34
|
incarnation: incarnationFromCell(sessionId, row.incarnation, "absent"),
|
|
18
35
|
placed: row.placement_kind !== null && row.placement_kind !== undefined,
|
|
36
|
+
deleting: token !== null && token !== undefined,
|
|
19
37
|
mirror: ext?.execution_role === "mirror",
|
|
20
38
|
cells: {
|
|
21
39
|
title: ext?.title === null || ext?.title === undefined ? null : String(ext.title),
|
|
@@ -23,6 +41,40 @@ function lockedRowFrom(dialect, sessionId, row, ext) {
|
|
|
23
41
|
},
|
|
24
42
|
};
|
|
25
43
|
}
|
|
44
|
+
export async function lockSessionRowOn(conn, dialect, sessionId, opts) {
|
|
45
|
+
const root = await lockSessionRootOn(rootRowsOnTx(conn), dialect, sessionId);
|
|
46
|
+
if (root === undefined)
|
|
47
|
+
return { locked: undefined };
|
|
48
|
+
const ensure = ensureSessionExtRowStatement(dialect, sessionId);
|
|
49
|
+
await conn.query(ensure.text, [...ensure.values]);
|
|
50
|
+
const extRead = binder(dialect);
|
|
51
|
+
const ext = (await conn.query(`SELECT execution_role, title, pinned, ${DELETING_TOKEN_COLUMN.name} FROM ${SESSION_EXT_TABLE} WHERE session_id = ${extRead.p(sessionId)} FOR UPDATE`, extRead.values)).rows[0];
|
|
52
|
+
const locked = lockedRowFrom(dialect, sessionId, root, ext);
|
|
53
|
+
return opts.logMark ? { locked, mark: await lockedLogMark(conn, dialect, sessionId, root.leaf_seq) } : { locked };
|
|
54
|
+
}
|
|
55
|
+
export async function withLandedRow(db, sessionId, landed, body, opts) {
|
|
56
|
+
return retryOnDeadlock(db.dialect, async () => {
|
|
57
|
+
const conn = await db.connect();
|
|
58
|
+
try {
|
|
59
|
+
await conn.begin();
|
|
60
|
+
const { locked } = await lockSessionRowOn(conn, db.dialect, sessionId, { logMark: false });
|
|
61
|
+
if (!judgeLandedRow(sessionId, landed, locked)) {
|
|
62
|
+
await conn.rollback();
|
|
63
|
+
return { landed: false };
|
|
64
|
+
}
|
|
65
|
+
const value = await body(conn);
|
|
66
|
+
await conn.commit();
|
|
67
|
+
return { landed: true, value };
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
await conn.rollback().catch(() => undefined);
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
conn.release();
|
|
75
|
+
}
|
|
76
|
+
}, opts?.alsoRetry);
|
|
77
|
+
}
|
|
26
78
|
async function lockedLogMark(conn, dialect, sessionId, leafSeq) {
|
|
27
79
|
const b = binder(dialect);
|
|
28
80
|
const last = await conn.query(`SELECT entry_id FROM session_event WHERE session_id = ${b.p(sessionId)} ORDER BY seq DESC LIMIT 1 FOR UPDATE`, b.values);
|
|
@@ -35,17 +87,8 @@ export async function writeSessionRowCellsSql(db, sessionId, cells, how, readAns
|
|
|
35
87
|
const conn = await db.connect();
|
|
36
88
|
try {
|
|
37
89
|
await conn.begin();
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
const extRead = binder(dialect);
|
|
41
|
-
let ext;
|
|
42
|
-
if (locked !== undefined) {
|
|
43
|
-
const ensure = ensureSessionExtRowStatement(dialect, sessionId);
|
|
44
|
-
await conn.query(ensure.text, [...ensure.values]);
|
|
45
|
-
ext = (await conn.query(`SELECT execution_role, title, pinned FROM ${SESSION_EXT_TABLE} WHERE session_id = ${extRead.p(sessionId)} FOR UPDATE`, extRead.values)).rows[0];
|
|
46
|
-
}
|
|
47
|
-
const mark = how.row.log === undefined || locked === undefined ? undefined : await lockedLogMark(conn, dialect, sessionId, locked.leaf_seq);
|
|
48
|
-
verdict = judgeSessionRowWrite(sessionId, how, locked === undefined ? undefined : lockedRowFrom(dialect, sessionId, locked, ext), () => {
|
|
90
|
+
const { locked, mark } = await lockSessionRowOn(conn, dialect, sessionId, { logMark: how.row.log !== undefined });
|
|
91
|
+
verdict = judgeSessionRowWrite(sessionId, how, locked, () => {
|
|
49
92
|
if (mark === undefined)
|
|
50
93
|
throw new Error(`writeSessionRowCellsSql: the judge asked session ${sessionId}'s log mark, but the expectation carries none`);
|
|
51
94
|
return mark;
|
|
@@ -21,26 +21,18 @@ import { type AcquiredSession, type PlacedSessionRow, type SessionHead, type Ses
|
|
|
21
21
|
import type { TiDBSessionStore } from "../stores-sql/tidb-session-store.js";
|
|
22
22
|
import type { SessionWriteHooks } from "../stores-sql/session-write-hooks.js";
|
|
23
23
|
import type { SqlDriver } from "./sql-driver.js";
|
|
24
|
+
import { type IdleSession, type IdleSessionCursor, type SessionKind, type SessionKindReading } from "../session-kind.js";
|
|
24
25
|
import { type ExecutionPlacementSeat } from "../execution-placement.js";
|
|
25
26
|
import { type InstructionSourceBaseline } from "../instruction-source-notice.js";
|
|
26
|
-
import { type RegisterReceipt, type SessionBirth, type WithdrawOutcome } from "../session-incarnation.js";
|
|
27
|
+
import { type RegisterReceipt, type SessionBirth, type SessionFace, type WithdrawOutcome } from "../session-incarnation.js";
|
|
27
28
|
import { type SessionDeletionFace } from "../session-deletion.js";
|
|
28
29
|
import { type ClientSessionRowWrite, type ReplaySessionRowWrite, type ReplaySessionRowWriteOutcome, type SessionRowAnswer, type SessionRowPatch, type SessionRowWriteOutcome } from "../session-row.js";
|
|
29
|
-
import type { SessionSummary } from "./store-contracts.js";
|
|
30
|
+
import type { SessionListQuery, SessionSummary } from "./store-contracts.js";
|
|
30
31
|
import type { SessionWorkspace } from "../session-workspace.js";
|
|
31
32
|
/** 座的面:座的公开成员(两方言同形 —— PG 孪生按结构赋给它,组合座里 tsc 判)。 */
|
|
32
33
|
export type SessionSeat = Pick<TiDBSessionStore, "retention" | "placements" | "durability" | "acquire" | "register" | "registerWithReceipt" | "deleteSessionIf" | "placementOf" | "listPlaced" | "headOf" | "touch" | "release" | "forget" | "fork" | "forkTo" | "exportEntries" | "listEntryIds" | "exportEntriesStream" | "importEntries" | "replaceEntries" | "beginImportStaging" | "readStagedEntries" | "sweepStagingSessions" | "size" | "dispose">;
|
|
33
|
-
/** 列表面的查询(`OwnerAwareSessionStore.listSessions`
|
|
34
|
-
export
|
|
35
|
-
owner?: string;
|
|
36
|
-
includeUnowned?: boolean;
|
|
37
|
-
cursor?: {
|
|
38
|
-
lastActivityAt: string;
|
|
39
|
-
sessionId: string;
|
|
40
|
-
};
|
|
41
|
-
limit: number;
|
|
42
|
-
q?: string;
|
|
43
|
-
}
|
|
34
|
+
/** 列表面的查询(`OwnerAwareSessionStore.listSessions` 的入参形;三店同一形)。 */
|
|
35
|
+
export type SessionListOptions = SessionListQuery;
|
|
44
36
|
/**
|
|
45
37
|
* 会话店的事务内钩(座锁住根行之后、写之前调;同一事务、同一连接):
|
|
46
38
|
* · 四个词同一只判官 {@link judgeSessionWrite}(local 店的写锁内同调这一只):`erase` 只判这一行的在删令牌(不是 ⇒ 拒 `SessionDeletionSupersededError`);其余认领在 ⇒ 拒 `SessionActiveRunError`;
|
|
@@ -49,6 +41,11 @@ export interface SessionListOptions {
|
|
|
49
41
|
* · 键控 fork(服务扩展)—— `record`:新行的 fork 键落旁表(新行是本事务刚插下的,本事务持着它的锁);`targetOf`:撞上已在的目标时的一次池读(属主 + fork 键)。
|
|
50
42
|
*/
|
|
51
43
|
export declare function createSqlSessionWriteHooks(db: Pick<SqlDriver, "dialect" | "query">): SessionWriteHooks;
|
|
44
|
+
/**
|
|
45
|
+
* 🔴 **视图谓词的 SQL 一句**(两方言同一函数;列表 lister 与老化候选面同调 —— local 店的同一判是 `session-kind.ts` 的 `sessionKindListed`):
|
|
46
|
+
* 缺省视图(`view` 缺席)⇒ 只有无种类的行;`view` 在场 ⇒ 恰那一种。`se` = 旁表 `session_ext` 的别名(LEFT JOIN:旁表行不在 = 无种类)。
|
|
47
|
+
*/
|
|
48
|
+
export declare function sessionKindSql(view: SessionKind | undefined, p: (v: unknown) => string): string;
|
|
52
49
|
export declare class SqlSessionStore implements SessionStore {
|
|
53
50
|
private readonly db;
|
|
54
51
|
/** 座(引擎座表的唯一写者)。 */
|
|
@@ -63,8 +60,10 @@ export declare class SqlSessionStore implements SessionStore {
|
|
|
63
60
|
constructor(db: SqlDriver, seatOn: (hooks: SessionWriteHooks) => SessionSeat);
|
|
64
61
|
acquire(...a: Parameters<SessionSeat["acquire"]>): Promise<AcquiredSession>;
|
|
65
62
|
register(sessionId: string, owner: string | null): Promise<void>;
|
|
66
|
-
/** 出生回执面(
|
|
67
|
-
registerWithReceipt(sessionId: string, owner: string | null): Promise<RegisterReceipt>;
|
|
63
|
+
/** 出生回执面(座逐字转发,种类一并转 —— 漏一层 = 种类在 SQL 上静默丢;`plugins/session-birth.ts`)。 */
|
|
64
|
+
registerWithReceipt(sessionId: string, owner: string | null, kind?: SessionKind): Promise<RegisterReceipt>;
|
|
65
|
+
/** 按 id 的种类读(`session-kind.ts` 的 `SessionKindFace`):一条 PK SELECT —— 根行的化身 + 旁表的种类(同一次读;旁表行不在 = 无种类)。不在 ⇒ `undefined`。 */
|
|
66
|
+
sessionKindOf(sessionId: string): Promise<SessionKindReading | undefined>;
|
|
68
67
|
/** 条件撤回面:座的条件删除 + 本部署的判据(启用标记 / 客户端写计数 / 别的 run / 本次 run 的部署行;同一事务)。 */
|
|
69
68
|
withdrawBirth(birth: SessionBirth, ownTaskId: string | undefined): Promise<WithdrawOutcome>;
|
|
70
69
|
placementOf(sessionId: string): Promise<SessionPlacementRecord | undefined>;
|
|
@@ -99,6 +98,22 @@ export declare class SqlSessionStore implements SessionStore {
|
|
|
99
98
|
* 写序与旁表的其余格写者同一条(根行 → 旁表;根行先 ⇒ 与认领事务、座的删除 / 导入同一锁序)。
|
|
100
99
|
*/
|
|
101
100
|
private fenceDeletion;
|
|
101
|
+
/**
|
|
102
|
+
* 老化条件的锁内判({@link SessionAgeOutExpectation};调用方持根行锁、旁表行已补并锁定 —— `readDeletingTokenOn` 之后):住客仍是候选那一位 ∧ 最后活动仍早于视界
|
|
103
|
+
* ∧ 种类仍是它 ∧ 当下无活引用(与托管留存同一只谓词;认领那一腿随后由围栏自己的判官再判一次,结局 `active`)。
|
|
104
|
+
* **全部是当前读**:住客与最后活动来自根行的锁定读;种类与活引用两读也带 `FOR UPDATE` —— MySQL 协议的可重复读下普通 SELECT 读的是一份快照(TiDB:事务起点的快照),
|
|
105
|
+
* 等根行锁期间别的事务提交的待决检查点 / 子代 / workflow 行会被它漏掉;锁定读读最新提交(与托管留存执行器的候选锁读同一形)。
|
|
106
|
+
*/
|
|
107
|
+
private ageOutHoldsOn;
|
|
108
|
+
/**
|
|
109
|
+
* 老化候选面(`OwnerAwareSessionStore.listIdleOfKind`;律 `src/session-kind.ts`):`session_meta` JOIN 旁表 —— 视图谓词同一只片段({@link sessionKindSql})∧ 最后活动早于视界
|
|
110
|
+
* ∧ 当下无活引用(与托管留存同一只谓词),**在删的行也交**(一次失败的自动删除撂下的在删行,两只 lister 都读不到它 —— 交给围栏:持有者已死 ⇒ 接管收完)。
|
|
111
|
+
* 最老先出,`(updated_at, session_id)` 升序 keyset 续页;走 `idx_session_ext_kind`。每读带语句期限(过期 ⇒ 这一句自己拒,调用方本拍停、下拍再来)。
|
|
112
|
+
*/
|
|
113
|
+
listIdleOfKind(kind: SessionKind, idleBefore: Date, page: {
|
|
114
|
+
readonly after?: IdleSessionCursor;
|
|
115
|
+
readonly limit: number;
|
|
116
|
+
}): Promise<IdleSession[]>;
|
|
102
117
|
get size(): number;
|
|
103
118
|
dispose(): void;
|
|
104
119
|
/**
|
|
@@ -135,9 +150,10 @@ export declare class SqlSessionStore implements SessionStore {
|
|
|
135
150
|
/** Cheap pre-LLM probe: "none" = session_meta row not yet REGISTERED (createRun fires before the Runner's session acquire — the titler retries),
|
|
136
151
|
* "untitled" / "titled" as read (no side-table row = untitled). */
|
|
137
152
|
probeTitle(sessionId: string): Promise<"none" | "untitled" | "titled">;
|
|
138
|
-
/** The auto-titler's write: lands ONLY when title IS NULL (a concurrent/prior title — the user's included — wins; writer order: `src/session-row.ts`)
|
|
139
|
-
*
|
|
140
|
-
|
|
153
|
+
/** The auto-titler's write: lands ONLY when title IS NULL (a concurrent/prior title — the user's included — wins; writer order: `src/session-row.ts`)
|
|
154
|
+
* AND the session row is still `landed` (the occupant the titler read at acceptance) — judged in the landed section (`withLandedRow`: lock the root row,
|
|
155
|
+
* the row-write judge). Returns whether this call set it. No session row / another occupant / being deleted ⇒ `false`, zero bytes. */
|
|
156
|
+
setTitleIfNull(sessionId: string, title: string, landed: SessionFace): Promise<boolean>;
|
|
141
157
|
/** 换源通告的基线读(一行 PK 读;列的三态读法见 `instruction-source-notice.ts`)。旁表行不在 ⇒ 读作「没记过」。语句期限 {@link BASELINE_IO_DEADLINE_MS}(过期 ⇒ 查询自己拒、连接销毁)。 */
|
|
142
158
|
readInstructionSource(sessionId: string): Promise<InstructionSourceBaseline>;
|
|
143
159
|
/**
|