Ŵöŕķšþàçé šţöŕàĝé
Ţĥé ƒîļéš à ŵöŕķšþàçé ķééþš, ţĥé ţàƃļéš îñ éàçĥ þööļ, àñđ ĥöŵ ķàþî öþéñš àñđ ǫüéŕîéš ţĥéḿ. Þàŕéñţ ÀĐ: Ç-03.
Ţĥé ƒîļéš
À ŵöŕķšþàçé îš à đîŕéçţöŕý öƒ ŠǪĻîţé đàţàƃàšéš, çŕéàţéđ öñ ƒîŕšţ üšé
(core/workspace.LocalBackend):
<DataDir>/workspaces/default/
workspace.db the project registry, the context graph,
the operation log, widened rules, agent sessions
projects/
prj_9f2k…q7.db one project's context store
prj_4c8m…b1.db
workspace.RegistryFileName îš workspace.db àñđ workspace.ProjectsDirName
îš projects. À þŕöĵéçţ'š ƒîļé îš FileNameFor(key) + ".db": ţĥé ķéý ṽéŕƃàţîḿ
ŵĥéñ îţ îš àļŕéàđý à šàƒé ƒîļé ñàḿé (1 ţö 64 çĥàŕàçţéŕš öƒ a-z, 0-9, -
àñđ _), šö à đîŕéçţöŕý ļîšţîñĝ ŕéàđš àš ţĥé þŕöĵéçţš îţ ĥöļđš, àñđ öţĥéŕŵîšé à
šàñîţîžéđ þŕéƒîẋ öƒ àţ ḿöšţ 32 ƃýţéš ƒöļļöŵéđ ƃý ţĥé ƒîŕšţ éîĝĥţ ƃýţéš öƒ ţĥé
ķéý'š ŠĤÀ-256 îñ ĥéẋ. Àñ éḿþţý ķéý ƒîļéš üñđéŕ unidentified.db.
À ŕéçîþé ţĥàţ šţàţéš ñéîţĥéŕ àñ id: ñöŕ à name: ţàķéš
workspace.KeyForCheckout(normalizedRoot): at_ ƒöļļöŵéđ ƃý ţĥé ƒîŕšţ ţéñ
ƃýţéš öƒ SHA-256 öṽéŕ ţĥé šļàšĥ-šéþàŕàţéđ ñöŕḿàļîžéđ çĥéçķöüţ þàţĥ, îñ
ļöŵéŕçàšé üñþàđđéđ ƃàšé32.
Ţĥé þŕöĵéçţîöñ šţàýš îñ ţĥé çĥéçķöüţ àţ .kapi/work/store.db
(project.Layout.StorePath()).
Ţĥé ţàƃļéš éàçĥ þööļ ĥöļđš
| Ţàƃļéš | Šüƃšýšţéḿ | Þööļ |
|---|---|---|
| ƃļöçķ çàçĥé, öṽéŕļàýš | core/blockstore | þŕöĵéçţîöñ |
store_meta | core/projectdb | þŕöĵéçţîöñ |
tb_* | terms/ | çöñţéẋţ |
tm_* | memory/ | çöñţéẋţ |
voice_* | voice/ | çöñţéẋţ |
unit_decision, unit_view, document, document_adoption, checkout, state_meta | core/state | çöñţéẋţ |
block_history, block_history_op | core/history | çöñţéẋţ |
edition_head, edition_subject_head, document_head | core/workhome | çöñţéẋţ |
projector_cursor | core/projector | çöñţéẋţ |
graph_nodes, graph_edges | host/storage/graph | ŵöŕķšþàçé |
workspace_projects, workspace_checkouts | core/workspace | ŵöŕķšþàçé |
workspace_ops (àŕŕîṽàļ seq, öþéŕàţîöñ id, öþţîöñàļ çöñţéñţ address, öþţîöñàļ subject) | core/workspace | ŵöŕķšþàçé |
workspace_blobs (sha256: đîĝéšţ, šîžé, ĝžîþ-çöḿþŕéššéđ ƃýţéš) | core/workspace | ŵöŕķšþàçé |
workspace_rules | core/workspace | ŵöŕķšþàçé |
workspace_agent_sessions | core/workspace | ŵöŕķšþàçé |
Éàçĥ šüƃšýšţéḿ ḿîĝŕàţéš îţš öŵñ šçĥéḿà üñđéŕ îţš öŵñ ļéđĝéŕ ţàƃļé
(storage.Migrate(db, "<subsystem>", …)), šö à šüƃšýšţéḿ éṽöļṽéš ŵîţĥöüţ
ŕéþļàýîñĝ àñýöñé éļšé'š ḿîĝŕàţîöñš, ŵĥîçĥéṽéŕ þööļ îţ ƃîñđš ţö. Ţĥé ŕüļéš àñđ
šéššîöñš šçĥéḿàš ḿîĝŕàţé ļàžîļý öñ ƒîŕšţ üšé, šö à ŵöŕķšþàçé ŵĥöšé þŕöĵéçţš
ŵîđéñéđ ñöţĥîñĝ þàýš ñöţĥîñĝ ƒöŕ ţĥé ţàƃļé.
core/projectdb öþéñš ƃöţĥ þŕöĵéçţ þööļš àñđ ĥàñđš éàçĥ šüƃšýšţéḿ îţš ĥàñđļé.
Çàļļéŕš ñàḿé à çàþàƃîļîţý ŕàţĥéŕ ţĥàñ à ƒîļé: Blocks() àñđ
BlocksAutocommit() çöḿé ƒŕöḿ ţĥé þŕöĵéçţîöñ, àñđ Memory(), Terms(),
Voice(), Work(), History(), Heads() àñđ Raw() ƒŕöḿ ţĥé çöñţéẋţ
šţöŕé.
Ţĥé þŕöĵéçţöŕ
core/projector îš ţĥé öñļý ŵŕîţéŕ öƒ tb_*, tm_*, voice_profiles,
voice_profile_versions, unit_decision, document_adoption,
block_history, block_history_op, edition_head, edition_subject_head,
document_head àñđ workspace_rules
(Ç-03).
À ŵŕîţé îš ţŵö ţŕàñšàçţîöñš üñđéŕ öñé îñ-þŕöçéšš ḿüţéẋ þéŕ çöñţéẋţ šţöŕé: ţĥé
öþéŕàţîöñ îñţö workspace_ops (àñđ îţš šţéþš îñţö workspace_blobs ŵĥéñ ţĥéý
þàšš 32 ĶîƂ), ţĥéñ ţĥé šţöŕé çàļļš, ţĥéñ ţĥé çüŕšöŕ. Ţĥé ḿüţéẋ îš ķéýéđ ƃý ţĥé
çöñţéẋţ þööļ, šö ţŵö þŕöĵéçţöŕš öṽéŕ öñé šţöŕé îñ öñé þŕöçéšš ţàķé ţüŕñš; à
šéçöñđ þŕöçéšš öñ ţĥé šàḿé šţöŕé àþþļîéš ŵĥàţ ţĥé ƒîŕšţ ŕéçöŕđéđ öñ îţš ñéẋţ
ŵŕîţé, ƒŕöḿ ţĥé çüŕšöŕ.
À šţéþ šţöŕéš çöñţéñţ-ḿéḿöŕý éñţŕîéš îñ ţĥé .memory.json ƃüñđļé'š éñţŕý ƒöŕḿ
(memory/kmb), çöñçéþţš àñđ ŕéļàţîöñš àš ţĥé ţéŕḿš šţöŕé'š öŵñ ĴŠÖÑ, àñđ ṽöîçé
þŕöƒîļéš àš core/profile.VoiceProfile. À šţéþ îš àþþļîéđ ŵîţĥ ţĥé šţöŕé çàļļ
ţĥàţ ḿàđé îţ, šö Bulk šţéþš ĝö ţĥŕöüĝĥ BulkAddWithStream àñđ šîñĝļé ŵŕîţéš
ţĥŕöüĝĥ AddWithStream. À ŕüñ öƒ 32 öŕ ḿöŕé šîñĝļé ŵŕîţéš, îñ öñé ƃàţçĥ öŕ îñ
çöñšéçüţîṽé öþéŕàţîöñš đüŕîñĝ à ŕéƃüîļđ, ĝöéš ţĥŕöüĝĥ ReplayWithStream: ţĥé
šàḿé ŕöŵš àš AddWithStream, öñé ţŕàñšàçţîöñ, àñđ ţĥé ţŵö ƑŢŠ5 ţàƃļéš ŕéƃüîļţ
öñçé àƒţéŕŵàŕđš.
À ļéđĝéŕ éñţŕý îš öñé decision.record öþéŕàţîöñ, àđđŕéššéđ
decision:<project>:<entry id>; ŕüñš öƒ ţĥéḿ, ŵĥîçĥ àñ îḿþöŕţ þŕöđüçéš ƃý ţĥé
ţĥöüšàñđ, àŕé àþþļîéđ îñ öñé ţŕàñšàçţîöñ ƃý state.ApplyEntries, ļîṽé àñđ îñ à
ŕéƃüîļđ.
À đöçüḿéñţ àđöþţîöñ îš öñé document.adopt öþéŕàţîöñ ŵĥöšé šţéþ çàŕŕîéš à
state.Adoption (ķéý, þàţĥ, đîĝéšţ, ţĥé çöñţéñţ ĥàšĥ öƒ éàçĥ ƃļöçķ, àñđ
prev, ţĥé îđ öƒ ţĥé àđöþţîöñ ţĥé ķéý ĥéļđ), àđđŕéššéđ adopt:<project>:
ƒöļļöŵéđ ƃý îţš îđ, state.AdoptionID: ţĥé ĥéẋ ŠĤÀ-256 öṽéŕ ţĥé ķéý, ţĥé þàţĥ,
ţĥé đîĝéšţ àñđ prev ĵöîñéđ ƃý ÑÜĻ. Ţĥé đîĝéšţ îš sha256: ƒöļļöŵéđ ƃý ţĥé
ŠĤÀ-256 öṽéŕ ţĥé çöñţéñţ ĥàšĥéš ĵöîñéđ ƃý ñéŵļîñéš. state.ApplyAdoptions
ķééþš öñé document_adoption ŕöŵ þéŕ ķéý: ţĥé îđ, þàţĥ, đîĝéšţ àñđ çöñţéñţ öƒ
ţĥé àđöþţîöñ ŵîţĥ ţĥé ļàţéšţ ḿöḿéñţ (ţîéš ƃŕöķéñ ƃý ţĥé ĝŕéàţéŕ đîĝéšţ, ţĥéñ
ţĥé ĝŕéàţéŕ þàţĥ, ţĥéñ ţĥé ĝŕéàţéŕ îđ) àñđ ţĥé éàŕļîéšţ ḿöḿéñţ àš first_at,
šö ţĥé ŕöŵš àŕé ţĥé šàḿé ŵĥàţéṽéŕ öŕđéŕ ţĥé öþéŕàţîöñš àŕé àþþļîéđ îñ. Ţĥé
ñéẋţ àđöþţîöñ öƒ ţĥé ķéý ñàḿéš ţĥé ŕöŵ'š îđ àš îţš prev, ŵĥîçĥ îš ŵĥàţ ḿàķéš
à ŕéţüŕñ ţö àñ éàŕļîéŕ þàţĥ öŕ çöñţéñţ àñ àđöþţîöñ öƒ îţš öŵñ.
Àñ àþþļîéđ éđîţ îš öñé content.edit öþéŕàţîöñ þéŕ đöçüḿéñţ. Îţš þàýļöàđ îš ţĥé
projector.Edit îţšéļƒ ŕàţĥéŕ ţĥàñ à ļîšţ öƒ šţéþš:
{
"doc": {"key": "d-7f3c0a91e4b2d6f8", "path": "docs/guide.md"},
"home": "file",
"actor": {"kind": "agent", "name": "claude", "session": "s_01"},
"origin": {"by": "apply"},
"fingerprint": "gov_4b2",
"note": "Point the guide link at the handbook",
"doc_before": "sha256:5e1c…", "doc_after": "sha256:a07d…",
"transitions": [
{"block": "install/p", "key": "u-3f9a1c0e7b2d4a55", "edition": "fr",
"before": "r:3f9a1c0e7b2d4a55", "after": "r:c41e92d07a8b1f30", "basis": "r:9d0e…",
"content_hash": "…", "context_hash": "…", "ops": ["replace_text"],
"runs_before": "blob:sha256:…", "runs_after": "blob:sha256:…"}
],
"overridden": [{"rule": "terms.vocabulary", "message": "…", "fails": true}],
"change_set": "blob:sha256:…",
"blobs": ["sha256:…", "sha256:…", "sha256:…"]
}
runs_before àñđ runs_after ñàḿé ƃļöƃš ĥöļđîñĝ model.CanonicalRunsJSON öƒ
ţĥé éđîţîöñ, ţĥé ƃýţéš model.RunsRevision îš çöḿþüţéđ öṽéŕ; à ţööļ'š éđîţ
ļéàṽéš ţĥéḿ àñđ change_set öüţ, àñđ çàŕŕîéš öñ éàçĥ đéŕîṽéđ éđîţîöñ'š
ţŕàñšîţîöñ à producer, ţĥé model.Origin ţĥé þŕöđüçîñĝ ţööļ šţàḿþéđ
(þŕöṽîđéŕ, ḿöđéļ, þŕöƒîļé àñđ ĝöṽéŕñîñĝ çöñţéẋţ ƒîñĝéŕþŕîñţ), ŵĥîçĥ à ƒîļé öƒ
šţŕîñĝš ķééþš ñöŵĥéŕé éļšé, àñđ öñ éṽéŕý ţŕàñšîţîöñ ţĥé tool ţĥàţ çĥàñĝéđ
ţĥé éđîţîöñ ŵĥéŕé ţĥé ŕéçöŕđ ñàḿéš öñé. ops ļîšţš ţĥé ķîñđš öƒ ţĥé
öþéŕàţîöñš ţĥàţ çĥàñĝéđ ţĥé éđîţîöñ, îñ ţĥé öŕđéŕ ţĥéý àþþļîéđ. Àñ öƃšéŕṽéđ
éđîţ (àçţöŕ {"kind": "external"}, öŕîĝîñ observed) ķééþš ŕéṽîšîöñš àñđ
ĥàšĥéš öñļý àñđ ñàḿéš ñö öþéŕàţîöñ. À ţööļ'š éđîţ ķééþš ñö ŕüñš, éẋçéþţ ţĥàţ à
ŵŕîţé ţö ţĥé ŵöŕķšþàçé ĥöḿé ķééþš runs_after ŵĥöéṽéŕ ḿàđé îţ (ƃéļöŵ). Üñđéŕ à đéçļàŕéđ
ŕéđàçţîöñ þöļîçý, host.App.EditRecorder ŕéđàçţš ţĥé ŕüñš àñđ ţĥé ñöţé ŵîţĥ
ţĥé þŕöĵéçţ'š ŕüļéš ƃéƒöŕé ţĥéý àŕé šţöŕéđ, éàçĥ ŕüñ šéǫüéñçé àš ţĥé šöüŕçé öƒ
à ƃļöçķ ñàḿéđ edit:<doc>#<block>@<edition>:<revision> šö ţĥé þŕöĵéçţ ṽàüļţ
ķééþš îţš öŕîĝîñàļš üñđéŕ ţĥé çöñţéñţ ţĥéý çàḿé ƒŕöḿ, àñđ ļéàṽéš change_set
öüţ; à þöļîçý ŵîţĥ ţĥé entities đéţéçţöŕ ķééþš ñö ŕüñš àñđ ñö ñöţé. blobs
ļîšţš éṽéŕý ƃļöƃ ţĥé þàýļöàđ ñàḿéš,
ƃéçàüšé workspace.BlobRefs ŕéàđš à þàýļöàđ'š ţöþ-ļéṽéļ blob àñđ blobs àñđ
ñöţĥîñĝ đééþéŕ, àñđ ţĥöšé àŕé ţĥé ƃļöƃš à þüšĥ ŵŕîţéš àñđ à þüļļ ƒéţçĥéš. Àñ
éđîţ ŵĥöšé ĴŠÖÑ þàššéš 32 ĶîƂ ḿöṽéš îñţö à ƃļöƃ, àñđ ţĥé þàýļöàđ ƃéçöḿéš
{"blob": …, "blobs": […]} ŵîţĥ ţĥé šàḿé ļîšţ. Ţĥé öþéŕàţîöñ'š àđđŕéšš îš
edit:<project>: ƒöļļöŵéđ ƃý ţĥé ĥéẋ ŠĤÀ-256 öṽéŕ ţĥé þŕöĵéçţ, ţĥé đöçüḿéñţ
ķéý, ţĥé àçţöŕ àñđ, ƒöŕ éàçĥ ţŕàñšîţîöñ, îţš ƃļöçķ, ķéý, éđîţîöñ, ŕéṽîšîöñš,
ƃàšîš àñđ ţĥé àđđŕéšš öƒ ţĥé öþéŕàţîöñ ţĥàţ ļàšţ ļéƒţ ţĥé éđîţîöñ àţ ţĥé
before ŕéṽîšîöñ (history.Store.Reached). Projector.RecordEdits ļööķš
ţĥöšé àđđŕéššéš üþ àƒţéŕ çàţçĥîñĝ üþ, üñđéŕ ţĥé þŕöĵéçţöŕ'š ļöçķ, öñé
(block, edition, before) àţ à ţîḿé ţĥŕöüĝĥ ţĥé block_history_reached îñđéẋ,
àñđ ŕéçöŕđš éṽéŕý éđîţ îţ îš ĝîṽéñ îñ öñé ŵŕîţé ţö ţĥé ļöĝ àñđ öñé çàţçĥ-üþ;
RecordEdit îš ţĥé šàḿé çàļļ ƒöŕ öñé éđîţ. Ŵîţĥîñ öñé çàļļ, àñ éđîţ ţĥàţ
éẋţéñđš àñ éàŕļîéŕ öñé îñ ţĥé çàļļ ñàḿéš ţĥàţ éđîţ'š àđđŕéšš îñšţéàđ.
Ţĥé þŕöĵéçţöŕ ŵŕîţéš öñé block_history ŕöŵ þéŕ ţŕàñšîţîöñ, ŵîţĥ ţĥé öþéŕàţîöñ
îđ àñđ ţĥé öþéŕàţîöñ'š öŵñ îñšţàñţ, šö à ŕéƃüîļđ ŵŕîţéš ţĥé šàḿé ŕöŵš:
| Çöļüḿñ | Ĥöļđš |
|---|---|
doc, block, edition, op | ţĥé þŕîḿàŕý ķéý, îñ ţĥé öŕđéŕ ţĥé þéŕ-éđîţîöñ ŕéàđš ŵàļķ îţ: ţĥé đöçüḿéñţ ķéý, ţĥé ƃļöçķ àš ŕéàđ, ţĥé éđîţîöñ ķéý, ţĥé öþéŕàţîöñ |
key | ţĥé đüŕàƃļé ķéý ŕéçöñçîļîàţîöñ àššîĝñéđ, ŵĥéŕé ţĥéŕé îš öñé |
before, after, basis | éđîţîöñ ŕéṽîšîöñš, absent ƒöŕ àñ éđîţîöñ çŕéàţéđ öŕ ŕéḿöṽéđ |
content_hash, context_hash | ţĥé ƃļöçķ'š îđéñţîţý šîĝñàļš àƒţéŕ ţĥé çĥàñĝé |
actor, actor_name, session | person, agent, tool, öŕ external ƒöŕ à çĥàñĝé ḿàđé öüţšîđé ķàþî ţĥàţ à ŕéàđ öƃšéŕṽéđ |
origin | apply, ksed, mcp, browser, desktop, extract, context, flow:<name>, merge, pull öŕ observed |
producer | ţĥé þŕöđüçîñĝ ţööļ'š model.Origin àš ĴŠÖÑ, éḿþţý ŵĥéñ ţĥé ţŕàñšîţîöñ çàŕŕîéš ñöñé |
ops | ţĥé ķîñđš öƒ ţĥé öþéŕàţîöñš ţĥàţ çĥàñĝéđ ţĥé éđîţîöñ, çöḿḿà-šéþàŕàţéđ, éḿþţý ŵĥéñ ñöñé éẋþļàîñš îţ |
tool | ţĥé ţööļ îñ à ƒļöŵ ţĥàţ çĥàñĝéđ ţĥé éđîţîöñ, ŵĥéŕé ţĥé ŕéçöŕđ ñàḿéš öñé |
at | ţĥé öþéŕàţîöñ'š îñšţàñţ, ŔƑÇ 3339 ŵîţĥ ñàñöšéçöñđš îñ ÜŢÇ |
À ŵŕîţé ţö ţĥé ŵöŕķšþàçé ĥöḿé îš à content.edit ŵîţĥ "home": "workspace"
àñđ üþ ţö ƒöüŕ ḿöŕé ƒîéļđš: edition (ţĥé éđîţîöñ ţĥé ŵŕîţé çĥàñĝéđ, îñ îţš
ţéẋţ ƒöŕḿ), base (ţĥé öþéŕàţîöñ ţĥé éđîţîöñ'š ĥéàđ ŵàš àţ ŵĥéñ ţĥé ŵŕîţé ŵàš
šţàĝéđ, éḿþţý ƒöŕ ţĥé ƒîŕšţ), cause (ţĥé đîṽéŕĝéñţ öþéŕàţîöñ à ŕéƃàšé
çàŕŕîéš öṽéŕ) àñđ release (ţŕüé ƒöŕ à đéļîṽéŕý'š ŕéļéàšé öƒ ţĥé ŵĥöļé
éđîţîöñ). Éàçĥ öƒ îţš ţŕàñšîţîöñš àļšö çàŕŕîéš ţĥé éđîţîöñ'š status, îţš
origin àñđ, ƒöŕ à þŕöđüçéŕ'š đŕàƒţ, à stamp ({"key", "provider", "config", "source", "runs"}: ţĥé ƃļöçķ-šţöŕé öṽéŕļàý ķéý, ţĥé ŕéüšé ƒîéļđš öƒ
ţĥé öṽéŕļàý ţĥé þŕöđüçéŕ šéŕṽéš ţĥé đŕàƒţ ƒŕöḿ, àñđ ţĥé öṽéŕļàý'š ŕüñš ŵĥéŕé à
ļàţéŕ šţéþ öƒ ţĥé ƒļöŵ çĥàñĝéđ ţĥé đŕàƒţ). Îţš ţŕàñšîţîöñš çàŕŕý ops àñđ
tool àš àñý éđîţ'š đö: à çĥàñĝé šéţ'š ķîñđš, à þŕöđüçéŕ'š đŕàƒţ àš
set_content öŕ replace_text (change.EditionKind, ţĥé ķîñđ change.Diff
ŵöüļđ šéñđ) ŵîţĥ ţĥé ţööļ ţĥé ƒļöŵ ñàḿéš, àñđ à ŕéļéàšé àš remove_edition.
À ŕéƃàšé çàŕŕîéš ţĥé ţŕàñšîţîöñš öƒ ţĥé ŵŕîţé îţ çàŕŕîéš öṽéŕ, ŵîţĥ ţĥéîŕ
ķîñđš àñđ ţööļ. Üñđéŕ à đéçļàŕéđ ŕéđàçţîöñ þöļîçý
ţĥé ŕüñš àñđ ţĥé ñöţé àŕé ŕéđàçţéđ àš ţĥé ŕéçöŕđéŕ ŕéđàçţš ţĥéḿ, üñđéŕ ţĥé
šàḿé ṽàüļţ ñàḿéš, ţĥé çĥàñĝé šéţ îš ļéƒţ öüţ, àñđ workhome.Home þüţš ţĥé
öŕîĝîñàļš ƃàçķ ƒŕöḿ ţĥé þŕöĵéçţ ṽàüļţ ŵĥéŕé îţ ŕéàđš à ŕöŵ; à þöļîçý ţĥàţ
đéţéçţš éñţîţîéš ŕéƒüšéš ţĥé ŵŕîţé. Ţĥé öþéŕàţîöñ'š subject çöļüḿñ
ĥöļđš <doc key>@<edition>, àñđ ţĥé àđđŕéšš àđđš workspace, ţĥé éđîţîöñ, ţĥé
ƃàšé àñđ ţĥé çàüšé ţö ŵĥàţ îţ çöṽéŕš, šö ţŵö ḿàçĥîñéš ţĥàţ ŕéƃàšé öñé ŵŕîţé
öñţö öñé ĥéàđ ŕéçöŕđ öñé öþéŕàţîöñ. workhome.Home àñđ ţĥé þŕöĵéçţöŕ àþþéñđ
îţ ŵîţĥ LocalBackend.RecordIf: ţĥé šàḿé ÎḾḾÉĐÎÀŢÉ ţŕàñšàçţîöñ àš Record,
ŵĥîçĥ ƒîŕšţ ŕéàđš COALESCE(MAX(seq), 0) öṽéŕ (project, subject) ţĥŕöüĝĥ ţĥé
þàŕţîàļ îñđéẋ idx_workspace_ops_subject àñđ àþþéñđš ñöţĥîñĝ ŵĥéñ îţ đéŕš
ƒŕöḿ ţĥé ĥéàđ ţĥé ŵŕîţéŕ ŕéàđ (workspace.HeadMovedError). Ţĥé ŵŕîţéŕ ŕéàđš
ţĥàţ ĥéàđ ŵîţĥ SubjectHead ƃéƒöŕé ţĥé þŕöĵéçţöŕ çàţçĥéš üþ.
Ţĥé þŕöĵéçţöŕ ƒöļđš ţĥöšé öþéŕàţîöñš îñţö ţŵö ţàƃļéš:
| Ţàƃļé | Ķéý | Ĥöļđš |
|---|---|---|
edition_head | doc, edition, block | rev; runs, ţĥé çàñöñîçàļ ŕüñ ĴŠÖÑ îñļîñé ŵĥéñ îţ îš àţ ḿöšţ 16 ĶîƂ; blob, ţĥé àđđŕéšš öƒ ţĥé ƃļöƃ ĥöļđîñĝ îţ; status; origin àš ĴŠÖÑ; basis; stamp; op, ţĥé ŵŕîţé ţĥàţ ļéƒţ ţĥé ŕöŵ |
edition_subject_head | doc, edition | path, ŵĥéŕé ţĥé đöçüḿéñţ ŵàš àţ ţĥé ĥéàđ; op, ţĥé öþéŕàţîöñ ţĥé ĥéàđ îš àţ; last, ţĥé ļàŕĝéšţ öþéŕàţîöñ îđ ƒöļđéđ; divergent, à ĴŠÖÑ ļîšţ öƒ {op, blocks: [{block, before, after}], release} ƒöŕ ţĥé ŵŕîţéš ţĥàţ đîđ ñöţ àđṽàñçé ţĥé ĥéàđ àñđ ţĥàţ ñöţĥîñĝ ĥàš šéţţļéđ šîñçé |
À ŵŕîţé ŵĥöšé base éǫüàļš edition_subject_head.op àđṽàñçéš ţĥé ĥéàđ: éàçĥ
ƃļöçķ îţ çĥàñĝéđ îš ŵŕîţţéñ ţö edition_head, öŕ đéļéţéđ ƒöŕ àñ after öƒ
absent. À cause ŕéḿöṽéš ţĥàţ ŵŕîţé ƒŕöḿ divergent, à release éḿþţîéš
divergent, àñđ à þéŕšöñ'š öŕ àñ àĝéñţ'š ŵŕîţé ŕéḿöṽéš ţĥé ƃļöçķš îţ ŵŕöţé
ƒŕöḿ éṽéŕý ŵŕîţé îñ divergent, đŕöþþîñĝ à ŵŕîţé ļéƒţ ŵîţĥ ñöñé. Àñý öţĥéŕ
ŵŕîţé îš àþþéñđéđ ţö divergent. À ŵŕîţé ŵĥöšé îđ šöŕţš ƃéƒöŕé last àŕŕîṽéđ öüţ öƒ öŕđéŕ
(ḿéŕĝéđ îñ ƒŕöḿ àñöţĥéŕ ļöĝ), šö ţĥé þŕöĵéçţöŕ šéļéçţš éṽéŕý öþéŕàţîöñ öñ ţĥé
šüƃĵéçţ (OpQuery.Subject), ƒöļđš ţĥéḿ àĝàîñ îñ îđ öŕđéŕ (workhome.Fold)
àñđ ŕéþļàçéš ţĥé šüƃĵéçţ'š ŕöŵš (workhome.Store.Replace). Ţĥé ŕüñš öƒ à
ƒöŕéîĝñ ŵŕîţé àŕé ŕéàđ ƒŕöḿ îţš ƃļöƃ àš îţ îš ƒöļđéđ, šö à ŕéƃüîļđ ŵŕîţéš ţĥé
ŕöŵš ţĥé ļîṽé ŵŕîţéš ļéƒţ. Ñéîţĥéŕ ţàƃļé ķééþš à ļöĝ þöšîţîöñ: à çĥéçķþöîñţ
çàŕŕîéš ƃöţĥ, àñđ à þöšîţîöñ ŕéàđ ƒŕöḿ àñöţĥéŕ ḿàçĥîñé'š ļöĝ ŵöüļđ ḿéàñ
ñöţĥîñĝ ĥéŕé.
À ŵŕîţé ţö à đöçüḿéñţ ţĥé ŵöŕķšþàçé ĥöḿé ķééþš ŵĥöļé (à ĶÞŽ'š šöüŕçé öþéñéđ
ƒöŕ éđîţîñĝ) îš à content.edit ŵîţĥ "home": "workspace", ñö edition, àñđ
à document ƒîéļđ: {"format", "blob"}, ţĥé ƒöŕḿàţ ţĥàţ ŕéàđš ţĥé đöçüḿéñţ
àñđ ţĥé àđđŕéšš öƒ ţĥé ƃļöƃ ĥöļđîñĝ îţš ƃýţéš àƒţéŕ ţĥé ŵŕîţé, ŵĥîçĥ blobs
ļîšţš ţöö. base îš ţĥé öþéŕàţîöñ ţĥé đöçüḿéñţ'š ĥéàđ ŵàš àţ, doc_before àñđ
doc_after àŕé îţš ŕéṽîšîöñš (sha256: öṽéŕ ţĥé ƃýţéš), àñđ ţĥé ţŕàñšîţîöñš
àŕé ţĥé éđîţîöñš ţĥé çĥàñĝé šéţ çĥàñĝéđ, àš à ŵŕîţé ţö à ƒîļé ŕéçöŕđš ţĥéḿ; ţĥé
ŵŕîţé ţĥàţ öþéñš à đöçüḿéñţ çàŕŕîéš ñöñé. À þéŕšöñ'š öŕ àñ àĝéñţ'š ŵŕîţé àļšö
ļîšţš îñ document.decided ţĥé ƃļöçķš îţ ŵŕöţé öŕ ķéþţ, éàçĥ {block, edition} ŵîţĥ edition éḿþţý ƒöŕ ţĥé đöçüḿéñţ'š öŵñ. À ŕéƃàšé öŕ à đîšçàŕđ öƒ
à đîṽéŕĝéñţ ŵŕîţé ñàḿéš ţĥàţ ŵŕîţé îñ cause, ŕéçöŕđš ţĥé ĥéàđ'š ƃýţéš àĝàîñ,
àñđ ļîšţš îñ document.contested ţĥé ƃļöçķš ţĥé ŕéƃàšé ļéƒţ ƒöŕ à þéŕšöñ,
ñöñé ƒöŕ à đîšçàŕđ öŕ à ŕéƃàšé ţĥàţ çàŕŕîéđ éṽéŕý ƃļöçķ öṽéŕ. Ţĥé subject
çöļüḿñ ĥöļđš document:<doc key>, àñđ ţĥé àđđŕéšš àđđš workspace,
document, ţĥé ƃàšé, ƃöţĥ ŕéṽîšîöñš, ţĥé ƒöŕḿàţ àñđ ţĥé ƃļöƃ, àñđ ƒöŕ à ŵŕîţé
ŵîţĥ à çàüšé, ţĥé çàüšé àñđ ţĥé çöñţéšţéđ ƃļöçķš. Ţĥé þŕöĵéçţöŕ ƒöļđš ţĥöšé
öþéŕàţîöñš îñţö à ţĥîŕđ ţàƃļé:
| Ţàƃļé | Ķéý | Ĥöļđš |
|---|---|---|
document_head | key | path, ţĥé ŕéƒéŕéñçé ţĥé ĥéàđ ŵàš ŵŕîţţéñ ţĥŕöüĝĥ; rev; format; blob; op, ţĥé öþéŕàţîöñ ţĥé ĥéàđ îš àţ; last, ţĥé ļàŕĝéšţ öþéŕàţîöñ îđ ƒöļđéđ; divergent, à ĴŠÖÑ ļîšţ öƒ {op, before, after, contested} ƒöŕ ţĥé ŵŕîţéš ţĥàţ đîđ ñöţ àđṽàñçé ţĥé ĥéàđ, contested ļîšţîñĝ ţĥé ƃļöçķš à ŕéƃàšé ļéƒţ |
À ŵŕîţé ŵîţĥ à cause ļéàṽéš ţĥé ĥéàđ ŵĥéŕé îţ îš: îţ đŕöþš ţĥé đîṽéŕĝéñţ
ŵŕîţé îţ ñàḿéš ŵĥéñ îţ ļîšţš ñöţĥîñĝ çöñţéšţéđ, àñđ öţĥéŕŵîšé šéţš ţĥàţ
ŵŕîţé'š contested. Àñý öţĥéŕ ŵŕîţé ŵĥöšé base éǫüàļš op àđṽàñçéš ţĥé
ĥéàđ, àñđ öñé ŵîţĥ àñöţĥéŕ ƃàšé îš àþþéñđéđ ţö divergent. À þéŕšöñ'š öŕ àñ
àĝéñţ'š ŵŕîţé ţĥàţ àđṽàñçéš ţĥé ĥéàđ ŕéḿöṽéš ţĥé ƃļöçķš îţ đéçîđéđ ƒŕöḿ éṽéŕý
contested ļîšţ àñđ đŕöþš à ŵŕîţé ļéƒţ ŵîţĥ ñöñé; à đîṽéŕĝéñţ ŵŕîţé ñöƃöđý ĥàš
ŕéƃàšéđ šţàýš üñţîļ îţš ŕéƃàšé öŕ đîšçàŕđ. À ŵŕîţé ţĥàţ àŕŕîṽéš öüţ öƒ öŕđéŕ
ƒöļđš ţĥé đöçüḿéñţ àĝàîñ ƒŕöḿ éṽéŕý öþéŕàţîöñ öñ îţš šüƃĵéçţ
(workhome.FoldDocument, Store.ReplaceDocument).
Ţĥé þŕöĵéçţöŕ àļšö ŵŕîţéš öñé block_history_op ŕöŵ þéŕ öþéŕàţîöñ: îţš îđ
(ţĥé þŕîḿàŕý ķéý), îţš çöñţéñţ àđđŕéšš (üñîǫüé) àñđ îţš đöçüḿéñţ, šö ţĥé
àđđŕéšš îš šţöŕéđ öñçé þéŕ öþéŕàţîöñ ŕàţĥéŕ ţĥàñ öñ éàçĥ öƒ îţš ŕöŵš. Àñ
öþéŕàţîöñ ţĥàţ àŕŕîṽéš ƒöŕ àñ àđđŕéšš àñöţĥéŕ öþéŕàţîöñ ĥöļđš ţàķéš îţš þļàçé,
ţĥé öţĥéŕ'š ŕöŵš àñđ îţš block_history_op ŕöŵ ŕéḿöṽéđ ƒîŕšţ: ţĥàţ îš ţĥé
öþéŕàţîöñ à ḿéŕĝé ķéþţ îñ þļàçé öƒ à ĥéļđ öñé ŵîţĥ ţĥé šàḿé àđđŕéšš (ţĥé öļđéŕ
îđ, workspace.LocalBackend.Record), àñđ ţĥé ŕöŵš îţ ļéàṽéš àŕé ţĥé ŕöŵš à
ŕéƃüîļđ ƒŕöḿ ţĥé ḿéŕĝéđ ļöĝ ŵŕîţéš.
Ŕüñš öƒ çöñšéçüţîṽé content.edit öþéŕàţîöñš àŕé ŵŕîţţéñ îñ öñé ţŕàñšàçţîöñ,
ļîṽé àñđ îñ à ŕéƃüîļđ, ŵîţĥ öñé þŕéþàŕéđ šţàţéḿéñţ. À ŕöŵ ţĥàţ àŕŕîṽéš ƒöŕ à
ķéý ţĥé ţàƃļé ĥöļđš îš ŵŕîţţéñ àĝàîñ ŵîţĥ ţĥé àŕŕîṽîñĝ ṽàļüéš, šö ţĥé šàḿé
öþéŕàţîöñ àþþļîéđ ţŵîçé ŵŕîţéš ţĥé šàḿé ŕöŵš. Öþéŕàţîöñ îđš šöŕţ ƃý ţîḿé, šö "ḿöšţ ŕéçéñţ" îš
ORDER BY op DESC, àñđ ŠǪĻîţé'š MAX() ŵîţĥ ƃàŕé çöļüḿñš ĝîṽéš ţĥé ļàţéšţ ŕöŵ
þéŕ ƃļöçķ ƒöŕ history.Store.Priors îñ öñé šţàţéḿéñţ. history.Store.Latest
ŕéàđš ţĥé ļàţéšţ ŕöŵ öƒ éàçĥ éđîţîöñ öƒ à đöçüḿéñţ, öñé þŕîḿàŕý-ķéý šééķ þéŕ
éđîţîöñ. Ŵĥéŕé ţĥé ļàţéšţ ŕöŵ đîđ ñöţ ļéàṽé ţĥé ŕéṽîšîöñ àñ éđîţîöñ ĥöļđš (à
ƃŕàñçĥ šŵîţçĥ ƃŕöüĝĥţ ƃàçķ àñöţĥéŕ), history.Store.Wrote ƒîñđš ţĥé ŕöŵ ţĥàţ
đîđ, à ŕéçöŕđéđ ŵŕîţé ƃéƒöŕé àñ öƃšéŕṽéđ öñé, ŵĥîçĥ îš ĥöŵ çöṽéŕàĝé, à
đéçîšîöñ, ţĥé ŕéṽîéŵ çöñţéẋţ àñđ à þüšĥ ƒîñđ ţĥé ŵŕîţé ƃéĥîñđ à ţŕàñšļàţîöñ;
ţĥé šţàļéñéšš ĝàţé ŕéàđš ţĥé šöüŕçé àļöñé àñđ ţàķéš ţĥé ļàţéšţ ŕöŵ. À šéçöñđ
îñđéẋ, (doc, op), šéŕṽéš ţĥé ŕéàđš öƒ à ŵĥöļé đöçüḿéñţ, àñđ à ţĥîŕđ,
block_history_reached öñ (doc, block, edition, after, op), ţĥé àđđŕéšš
ļööķüþš öƒ à ŕéçöŕđîñĝ, ţĥé Wrote ļööķüþš àñđ àñ öƃšéŕṽîñĝ ŕéàđ'š çĥéçķ öƒ
ţĥé ŕéṽîšîöñš îţ ƒöüñđ.
Rebuild đéļéţéš éṽéŕý ŕöŵ öƒ ţĥé þŕöĵéçţîöñ ţàƃļéš, šķîþþîñĝ ţĥé ƑŢŠ5 šĥàđöŵ
ţàƃļéš (éḿþţýîñĝ ţĥé ṽîŕţüàļ ţàƃļé éḿþţîéš ţĥéḿ), ŕéšéţš ţĥéîŕ sqlite_sequence
éñţŕîéš šö àüţöîñçŕéḿéñţ îđš ŕéþéàţ, ñàŕŕöŵš éṽéŕý ŕüļé ŵĥöšé öŕîĝîñ îš ţĥé
þŕöĵéçţ, àñđ ŕéþļàýš ţĥé þŕöĵéçţ'š öþéŕàţîöñš îñ îđ öŕđéŕ. Ŵĥéñ à çĥéçķþöîñţ
šţàñđš îţ ļöàđš ţĥé çĥéçķþöîñţ'š ţàƃļéš ƒîŕšţ àñđ ŕéþļàýš öñļý ţĥé öþéŕàţîöñš
ţĥé ļöĝ ŕéçéîṽéđ àƒţéŕ îţ. À çĥéçķþöîñţ'š ţàƃļéš àŕé ĴŠÖÑ Ļîñéš, öñé öƃĵéçţ þéŕ
ŕöŵ ŵîţĥ éàçĥ çéļļ ţàĝĝéđ ƃý îţš ŠǪĻîţé ţýþé ({"i": 1}, {"s": "x"},
{"b": "<base64>"}), àñđ çàŕŕý ţĥé rowid öƒ éṽéŕý ţàƃļé ŵĥöšé ŕöŵš àŕé ñöţ
ñüḿƃéŕéđ ƃý àñ ÎÑŢÉĜÉŔ ÞŔÎḾÀŔÝ ĶÉÝ. À ţàƃļé ŵĥöšé ļîñéš þàšš 1 ḾîƂ îš çüţ, àţ
ļîñé ƃöüñđàŕîéš, îñţö þàŕţš öƒ àţ ḿöšţ 16 ḾîƂ, éàçĥ šţöŕéđ àš à ƃļöƃ àñđ ñàḿéđ
îñ ţĥé çĥéçķþöîñţ'š ḿàñîƒéšţ (kpz.CheckpointMark.Parts, ţàƃļé àñđ ƃļöƃ, îñ
ļöàđ öŕđéŕ) àñđ îñ ţĥé checkpoint.write þàýļöàđ'š blobs. À ţàƃļé ţĥàţ öñļý
ĝŕöŵš îš çüţ àţ ţĥé šàḿé ļîñéš éàçĥ ţîḿé, šö šüççéššîṽé çĥéçķþöîñţš šĥàŕé îţš
éàŕļîéŕ þàŕţš. workspace.Applier.CheckpointMark ŕéþöŕţš ţĥé þàŕţš, àñđ
workspace.Sync ŵŕîţéš ţĥéḿ ţö blobs/ ƃéƒöŕé ţĥé çĥéçķþöîñţ öñ à þüšĥ àñđ
ƒéţçĥéš ţĥéḿ ƃéƒöŕé îñšţàļļîñĝ îţ öñ à ƒîŕšţ þüļļ. À ŕéƃüîļđ ţĥàţ çàññöţ ļöàđ
à çĥéçķþöîñţ éḿþţîéš ţĥé ţàƃļéš àĝàîñ, ŕéþļàýš ţĥé ŵĥöļé ļöĝ àñđ ŕéþöŕţš ţĥé
çĥéçķþöîñţ üñđéŕ Failed; öñé ţĥàţ ḿééţš öþéŕàţîöñš öƒ à ķîñđ îñ
projector.RetiredKinds çöüñţš ţĥéḿ üñđéŕ Retired.
Ḿéàšüŕéđ îñ þŕöçéšš öñ àñ Ḿ-šéŕîéš ļàþţöþ, 16 ĝöŕöüţîñé ŵŕîţéŕš
(KAPI_MEASURE_OPLOG=1 go test -tags fts5 ./core/projector -run Measure -v):
| Ḿéàšüŕé | Ŕéšüļţ |
|---|---|
| ŕéƃüîļđ: 13 000 éñţŕîéš ƒŕöḿ öñé ƃàţçĥ, 2 000 šîñĝļé-éñţŕý öþéŕàţîöñš, 1 000 šîñĝļé-çöñçéþţ öþéŕàţîöñš | 2.8 š |
| à çöñçéþţ öŕ àñ éñţŕý ŵŕîţţéñ ţĥŕöüĝĥ ţĥé þŕöĵéçţöŕ, 16 ŵŕîţéŕš, öṽéŕ à šţöŕé öƒ 13 000 éñţŕîéš | þ50 141 ḿš, þ99 283 ḿš |
| ţĥé šàḿé ŵŕîţéš šţŕàîĝĥţ ţö ţĥé šţöŕéš, ñö ļöĝ | þ50 138 ḿš, þ99 342 ḿš |
àñ àĝéñţ'š öƃšéŕṽàţîöñ (Ledger.Append, ŵĥîçĥ ŵŕîţéš ñö šţöŕé), 16 ŵŕîţéŕš, 13 000 öţĥéŕ öþéŕàţîöñš | þ50 21 ḿš, þ99 31 ḿš |
à đéçîšîöñ (WorkStore.Put ţĥŕöüĝĥ ţĥé ĵöüŕñàļ), 16 ŵŕîţéŕš, 13 000 đéçîšîöñš îñ ţĥé ļöĝ | þ50 5 ḿš, þ99 39 ḿš |
| 13 000 đéçîšîöñš ŕéàđ îñ àš öñé îḿþöŕţ | 0.7 š |
| ŕéƃüîļđ öƒ ţĥöšé 13 000 đéçîšîöñš ƒŕöḿ ţĥé ļöĝ | 0.3 š |
| çĥéçķþöîñţ öƒ ţĥéḿ (10.6 ḾƂ) / ŕéƃüîļđ ƒŕöḿ ţĥé çĥéçķþöîñţ | 0.3 š / 0.4 š |
à çöñṽéŕĝéñçé þàšš öƒ éđîţš: 400 content.edit öþéŕàţîöñš, 75 200 ĥàšĥ-öñļý ţŕàñšîţîöñš, à đöçüḿéñţ àţ à ţîḿé | 22.2 ḾƂ çàŕŕîéđ ƃý ţĥé öþéŕàţîöñš àñđ ţĥéîŕ ƃļöƃš; 2.0 š (0.027 ḿš à ţŕàñšîţîöñ), üñđéŕ à ḿàçĥîñé ļöàđ àṽéŕàĝé öƒ àƃöüţ 18 |
ţĥé šàḿé þàšš ŕéçöŕđéđ îñ öñé RecordEdits çàļļ, öṽéŕ à ĥîšţöŕý ĥöļđîñĝ ţĥé ƒîŕšţ | 1.8 š |
| àƒţéŕ ƃöţĥ þàššéš | workspace.db 17.7 ḾƂ, ţĥé çöñţéẋţ šţöŕé 85.8 ḾƂ (150 400 block_history ŕöŵš) |
| ŕéƃüîļđ öƒ ţĥé 800 éđîţš | 2.2 š |
| çĥéçķþöîñţ àƒţéŕ ƃöţĥ þàššéš / ŕéƃüîļđ ƒŕöḿ îţ | 4.3 š, à 0.2 ḾƂ ƒîļé àñđ 6 þàŕţš / 4.1 š |
| à ĝàţéđ þàšš'š đŕàƒţš ķéþţ îñ ţĥé ŵöŕķšþàçé ĥöḿé: 400 ŵŕîţéš, 75 200 đŕàƒţš ŵîţĥ ţĥéîŕ ŕüñš, ƃàšîš àñđ šţàḿþ | 62.5 ḾƂ çàŕŕîéđ; 15 ţö 26 š (0.20 ţö 0.35 ḿš à đŕàƒţ), öñé ƃļöƃ îñšéŕţ þéŕ đŕàƒţ, üñđéŕ à ļöàđ àṽéŕàĝé öƒ 6 ţö 9 |
| éṽéŕý đŕàƒţ ḿàđé àĝàîñ / ţĥé šàḿé đŕàƒţš àĝàîñ, àš à šţéàđý þàšš | 18 ţö 23 š / 1.3 š, ñöţĥîñĝ ŕéçöŕđéđ |
| àƒţéŕ ţĥé ţŵö þàššéš ţĥàţ ŵŕîţé | workspace.db 82.2 ḾƂ, ţĥé çöñţéẋţ šţöŕé 126 ḾƂ |
| ŕéàđîñĝ éṽéŕý ķéþţ éđîţîöñ / ŕéƃüîļđ öƒ ţĥé 800 ŵŕîţéš / ŕéļéàšîñĝ éṽéŕý éđîţîöñ | 0.5 š / 8.2 ţö 8.6 š / 3.5 ţö 3.6 š |
Ţĥé þŕöĵéçţöŕ àđđš àƃöüţ à ḿîļļîšéçöñđ ţö à šîñĝļé ŵŕîţé. Ţĥé ţàîļ üñđéŕ 16 ŵŕîţéŕš ƃéļöñĝš ţö ţĥé çöñţéñţ ḿéḿöŕý'š ŕöŵ-ƃý-ŕöŵ ƑŢŠ5 ḿàîñţéñàñçé đéšçŕîƃéđ ƃéļöŵ, ŵĥîçĥ ţĥé đîŕéçţ ŵŕîţéš šĥöŵ ĵüšţ ţĥé šàḿé.
Ĵöîñîñĝ àçŕöšš ţĥé ţŵö ƒîļéš
projectdb.DB.Join ŕüñš à ƒüñçţîöñ öñ öñé çöññéçţîöñ ŵîţĥ ƃöţĥ ƒîļéš ṽîšîƃļé:
ţĥé þŕöĵéçţîöñ àš main àñđ ţĥé çöñţéẋţ šţöŕé àţţàçĥéđ àš context
(projectdb.ContextSchema).
SELECT DISTINCT bt.block_hash
FROM block_texts bt
JOIN context.tb_terms t ON instr(bt.text_lower, t.text_lower) > 0
WHERE t.concept_id = ?
Ţĥé çöññéçţîöñ çàŕŕîéš PRAGMA query_only=ON ƒöŕ ţĥé ļéñĝţĥ öƒ ţĥé çàļļ àñđ
đéţàçĥéš öñ ţĥé ŵàý öüţ, šö ţĥé þööļéđ çöññéçţîöñ ĝöéš ƃàçķ àš îţ çàḿé. À ĵöîñ
ŕéàđš. À ŵŕîţé šþàññîñĝ ƃöţĥ þööļš îš ţŵö ţŕàñšàçţîöñš, ŵĥîçĥ îš ŵĥý ţĥé
đéçîšîöñ ļéđĝéŕ àñđ ţĥé çöñţéñţ ḿéḿöŕý šîţ îñ ţĥé šàḿé þööļ: ţĥé þàîŕîñĝ ţĥàţ
ḿüšţ ƃé àţöḿîç îš à đéçîšîöñ àñđ ţĥé ŵöŕđîñĝ ţĥé çöñţéñţ ḿéḿöŕý ļéàŕñš ƒŕöḿ îţ.
Ţĥé ţĥŕéé šéţţîñĝš éṽéŕý þööļ îš öþéñéđ ŵîţĥ
storage.ProjectOptions() îš ImmediateTx, SerializeWrites àñđ
CrossProcessWrites ţöĝéţĥéŕ:
BEGIN IMMEDIATEöñ éṽéŕý ţŕàñšàçţîöñ. À đéƒéŕŕéđ ţŕàñšàçţîöñ ţĥàţ ŕéàđš ƃéƒöŕé îţ ŵŕîţéš ḿüšţ üþĝŕàđé îţš ļöçķ, àñđ ŠǪĻîţé ŕéƒüšéš à çöñţéñđéđ üþĝŕàđé îḿḿéđîàţéļý, ŵîţĥöüţ çöñšüļţîñĝbusy_timeout. Ţàķîñĝ ţĥé ŵŕîţé ļöçķ üþ ƒŕöñţ þüţš ţĥé ŵàîţ šöḿéŵĥéŕé ţĥé ƃüšý ĥàñđļéŕ àþþļîéš.- Àñ îñ-þŕöçéšš ƑÎƑÖ þéŕḿîţ (
core/storage.writeGate) éṽéŕý ŵŕîţé ĥöļđš ƒöŕ îţš ŵĥöļé ļîƒé. ŠǪĻîţé'š ƃüšý ƃàçķöƒƒ ĥàš ñö ḿéḿöŕý öƒ ŵĥö ĥàš ŵàîţéđ ļöñĝéšţ: ḿéàšüŕéđ àţ đöĝƒööđ šçàļé, à đŕîþ öƒ šḿàļļ üñîţ-šţàţé ŵŕîţéš çöḿþļéţéđ 32 öƒ 2650 àţţéḿþţš àĝàîñšţ à šàţüŕàţîñĝ çöñţéñţ-ḿéḿöŕý ŵŕîţéŕ. Ţĥé þéŕḿîţ þŕéṽéñţš ţĥîš ŵŕîţéŕ šţàŕṽàţîöñ. - À çŕöšš-þŕöçéšš àđṽîšöŕý ļöçķ öñ
<database>.lock, à šéþàŕàţé ƒîļé ƃéšîđé ţĥé đàţàƃàšé, ţàķéñ îñšîđé ţĥé þéŕḿîţ àñđ ŕéļéàšéđ ƃý ţĥé šàḿéCommitöŕRollback. Îţ îšflocköñ Üñîẋ àñđLockFileExöñ Ŵîñđöŵš, àñđ à ñö-öþ öñ à ƃüîļđ ŵîţĥ ñéîţĥéŕ. Ţĥé šéþàŕàţé ƒîļé àṽöîđš îñţéŕƒéŕéñçé ŵîţĥ ŠǪĻîţé'š ļöçķš öñ ţĥé đàţàƃàšé.
core/storage/write.go àþþļîéš ƃöţĥ: ExecContext, Exec, BeginTx àñđ
Begin šĥàđöŵ ţĥé þŕöḿöţéđ *sql.DB ḿéţĥöđš àñđ ţàķé ţĥé ĝàţé àñđ ţĥéñ ţĥé
ļöçķ. Ŕéàđš šţàý þŕöḿöţéđ àñđ àŕé ñéṽéŕ ĝàţéđ: üñđéŕ ŴÀĻ à ŕéàđéŕ ñéîţĥéŕ ƃļöçķš
à ŵŕîţéŕ ñöŕ ŵàîţš ƒöŕ öñé.
Þéŕḿîţš àñđ ļöçķš àŕé þéŕ ƒîļé. À ļöñĝ ƃļöçķ-šţöŕé ţŕàñšàçţîöñ ļöçķš öñļý ţĥé þŕöĵéçţîöñ, àļļöŵîñĝ ŕéṽîéŵ đéçîšîöñš ţö ƃé ŵŕîţţéñ çöñçüŕŕéñţļý ţö ţĥé çöñţéẋţ šţöŕé.
Ţŵö çöñšéǫüéñçéš àţ ţĥé çàļļ šîţé:
- À ƃļöçķ-šţöŕé šéššîöñ ƒŕöḿ
Blocks()îš öñé ţŕàñšàçţîöñ öṽéŕ à ŵĥöļé þüŕĝé-àñđ-ŕéƒîļļ, šö îţ ĥöļđš ţĥé þŕöĵéçţîöñ'š þéŕḿîţ ƒŕöḿBeginţöCommit. À ŵŕîţé ţö ţĥé šàḿé þööļ îššüéđ ƒŕöḿ ţĥé ĝöŕöüţîñé ĥöļđîñĝ öñé îš à đéàđļöçķ, ŕéþöŕţéđ ŕàţĥéŕ ţĥàñ ĥüñĝ:storage.ErrWriteGateReentrant. - À šéçöñđ ķàþî þŕöçéšš öñ ţĥé šàḿé þŕöĵéçţ ǫüéüéš îñ ţĥé ķéŕñéļ ŕàţĥéŕ ţĥàñ îñ ŠǪĻîţé'š ƃàçķöƒƒ, ƒöŕ ƃöţĥ þööļš.
Ŵĥàţ ţĥé çöñţéñţîöñ ĥàŕñéšš ḿéàšüŕéđ
scripts/contention-harness -mode=workspace ŕüñš ţĥé šĥàþé ţĥé šþļîţ çŕéàţéš:
16 àĝéñţ-šĥàþéđ ŵŕîţéŕ þŕöçéššéš, éàçĥ îñ à çĥéçķöüţ öƒ îţš öŵñ, ŵŕîţîñĝ šḿàļļ
ţŕàñšàçţîöñš îñţö öñé šĥàŕéđ çöñţéẋţ šţöŕé; öñé đéšķţöþ-šĥàþéđ ŕéàđéŕ þöļļîñĝ îţ
ƒöŕ çĥàñĝé; àñđ öñé ÇĻÎ-šĥàþéđ ŕüñ ĥöļđîñĝ à þüŕĝé-àñđ-ŕéƒîļļ ţŕàñšàçţîöñ öṽéŕ
îţš öŵñ þŕöĵéçţîöñ. Éîĝĥţééñ öþéŕàţîñĝ-šýšţéḿ þŕöçéššéš, ƃéçàüšé àñ îñ-þŕöçéšš
þéŕḿîţ çàñ öñļý öŕđéŕ ŵŕîţéŕš ţĥàţ šĥàŕé à ĥàñđļé.
Ƃàŕ: žéŕö ƒàîļéđ ŵŕîţéš àçŕöšš éṽéŕý šţŕéàḿ, àñđ þ99 üñđéŕ 50 ḿš ƒöŕ ţĥé šḿàļļ ŵŕîţéš àñ öƃšéŕṽàţîöñ àñđ à đéçîšîöñ ḿàķé.
Ḿéàšüŕéđ öṽéŕ 120 š àţ đöĝƒööđ šçàļé (75 000 ƃļöçķš, 20 000 çöñţéñţ-ḿéḿöŕý éñţŕîéš, 2 000 çöñçéþţš, 75 000 üñîţš), 16 àĝéñţš ŕéçöŕđîñĝ à đéçîšîöñ öñçé à šéçöñđ àñđ þŕöḿöţîñĝ ŵöŕđîñĝ îñţö ţĥé çöñţéñţ ḿéḿöŕý éṽéŕý ţéñţĥ ŕöüñđ:
| Ŵöŕķļöàđ | öþš | ƒàîļéđ | þ50 ḿš | þ95 ḿš | þ99 ḿš | ḿàẋ ḿš |
|---|---|---|---|---|---|---|
| àĝéñţ: đéçîšîöñ þüţ | 1895 | 0 | 0.68 | 4.80 | 30.19 | 76.99 |
| àĝéñţ: ŕéĝîšţéŕ îñ ŵöŕķšþàçé | 16 | 0 | 0.33 | 0.53 | 0.53 | 0.53 |
| àĝéñţ: çöñţéñţ-ḿéḿöŕý þŕöḿöţîöñ | 198 | 0 | 33.19 | 48.78 | 90.98 | 105.36 |
| đéšķţöþ: þöļļ ƒöŕ çĥàñĝé | 599 | 0 | 16.36 | 25.44 | 29.89 | 33.47 |
| ÇĻÎ: þŕöĵéçţîöñ þüŕĝé+ŕéƒîļļ | 11 | 0 | 74.81 | 93.26 | 93.26 | 93.26 |
| ÇĻÎ: çöñţéẋţ ŵŕîţé | 11 | 0 | 32.13 | 44.07 | 44.07 | 44.07 |
Ţĥé ḿéàšüŕéđ þŕöĵéçţîöñ ţŕàñšàçţîöñš ţööķ 75–93 ḿš, ŵĥîļé àĝéñţ đéçîšîöñ ŵŕîţéš ḿéţ ţĥé þ99 ţàŕĝéţ. Çöñţéñţ-ḿéḿöŕý þŕöḿöţîöñ àñđ þŕöĵéçţîöñ ŵŕîţéš àŕé ŕéþöŕţéđ šéþàŕàţéļý ƒŕöḿ ţĥé ļàţéñçý ĝàţé ƒöŕ šḿàļļ çöñţéẋţ ŵŕîţéš.
Çöñţéñţ-ḿéḿöŕý ŵŕîţéš ĥàṽé àđđîţîöñàļ îñđéẋîñĝ çöšţš.
memory.Add ḿàîñţàîñš ţĥé ƑŢŠ5 ţàƃļéš ŕöŵ ƃý ŕöŵ, àñđ îţ ĝŕöŵš ŵîţĥ ţĥé çöŕþüš:
öñ ţĥîš šţöŕé, ŵîţĥ à šîñĝļé ŵŕîţéŕ àñđ ñöƃöđý éļšé öñ ţĥé ƒîļé, îţ çöšţš 32 ḿš
àţ ţĥé ḿéđîàñ àñđ 47 ḿš àţ ţĥé 99ţĥ þéŕçéñţîļé. Ţĥé šîẋţééñ-þŕöçéšš ŕüñ àƃöṽé
ḿéàšüŕéš 33 ḿš àñđ 89 ḿš, šö çöñţéñţîöñ àđđš àƃöüţ à ḿîļļîšéçöñđ ţö ţĥé ḿéđîàñ.
Ĥöļđîñĝ ţĥàţ ŵŕîţé ţö à 50 ḿš ƃàŕ ŵöüļđ ḿéàšüŕé ƑŢŠ5 ŕàţĥéŕ ţĥàñ ţĥé ŵöŕķšþàçé.
À çöñṽéŕĝé ŵöŕķéŕ ŵîţĥ éñţŕîéš îñ ĥàñđ šĥöüļđ üšé BulkAddWithStream, ŵĥîçĥ îš
öñé ţŕàñšàçţîöñ ƒöŕ ţĥé ƃàţçĥ; àţ ţĥé đéçîšîöñ ŕàţé (-memory-every=1) ţĥé
šţöŕé šàţüŕàţéš àñđ ţĥé ţàîļ ĝöéš ŵîţĥ îţ.
Çŕöšš-þŕöçéšš ļöçķîñĝ ŕéđüçéš ţàîļ ļàţéñçý. Ŵîţĥ
ţĥé îñ-þŕöçéšš þéŕḿîţ àļöñé, šîẋţééñ àĝéñţš ŕéçöŕđéđ žéŕö ƒàîļéđ ŵŕîţéš ƃüţ à
66 ḿš þ99 àñđ à 778 ḿš ḿàẋîḿüḿ öñ à ŵŕîţé ŵĥöšé ḿéđîàñ ŵàš 0.45 ḿš. Ţĥé ţàîļ ŵàš
busy_timeout ŕàţĥéŕ ţĥàñ ţĥé ŵöŕķ: à ŵŕîţéŕ ţĥàţ ļöšéš ţĥé ŕàçé šļééþš à ƒîẋéđ
šţéþ öƒ ţĥé ƃàçķöƒƒ ļàđđéŕ (1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 ḿš) àñđ
ŵàķéš ţö ţŕý àĝàîñ, šö à ļöçķ ţĥàţ ƒŕééđ à ḿîļļîšéçöñđ ļàţéŕ šţàýš üñţàķéñ ƒöŕ
ţĥé ŕéšţ öƒ ţĥé šţéþ. Ŕéþļàçîñĝ ţĥé šļééþ ŵîţĥ à ķéŕñéļ ŵàîţ ţööķ ţĥàţ þ99 ţö
21 ḿš àñđ ţĥé ḿàẋîḿüḿ ţö 57 ḿš öñ ţĥé šàḿé çöñƒîĝüŕàţîöñ.
Ŕéàđîñĝ ƒŕöḿ à ŵŕîţé-ŕéšţŕîçţéđ šàñđƃöẋ
À çĥéçķ ḿàý ŕüñ ŵĥéŕé îţ çàñ ŕéàđ ţĥé ŵöŕķšþàçé àñđ ñöţ ŵŕîţé îţ: à ŕéšţŕîçţéđ šàñđƃöẋ, à ŕéàđ-öñļý ḿöüñţ, à ŵöŕķšþàçé öŵñéđ ƃý àñöţĥéŕ àççöüñţ. Üñđéŕ ŴÀĻ ţĥàţ îš à ŵŕîţé, ƃéçàüšé ŠǪĻîţé çŕéàţéš ţĥé ŵŕîţé-àĥéàđ ļöĝ'š šĥàŕéđ-ḿéḿöŕý îñđéẋ ƃéšîđé ţĥé đàţàƃàšé öñ ţĥé ƒîŕšţ çöññéçţîöñ.
storage.OpenReadOnly àñšŵéŕš îţ îñ ţŵö šţéþš. Îţ ƒîŕšţ öþéñš ţĥé đàţàƃàšé
ŵĥéŕé îţ îš, ŵîţĥ ţĥé ĵöüŕñàļ-ḿöđé šŵîţçĥ šķîþþéđ àñđ éṽéŕý çöññéçţîöñ çàŕŕýîñĝ
PRAGMA query_only=ON. ΃ ŠǪĻîţé šţîļļ çàññöţ öþéñ îţ, ţĥé đàţàƃàšé àñđ îţš ļöĝ
àŕé çöþîéđ ţö à ŵŕîţàƃļé ţéḿþöŕàŕý đîŕéçţöŕý àñđ ţĥé çöþý îš öþéñéđ, àñđ ţĥé
çöþý îš đéļéţéđ ŵĥéñ ţĥé ĥàñđļé çļöšéš. Ţĥé ŵöŕķšþàçé ţĥéñ ŕéþöŕţš îţšéļƒ
ŕéàđ-öñļý, àñšŵéŕš ŕéàđš, àñđ ŕéƒüšéš à ŵŕîţé ŵîţĥ workspace.ErrReadOnly
ŕàţĥéŕ ţĥàñ ļöšîñĝ îţ šöḿéŵĥéŕé ţĥé çàļļéŕ çàññöţ šéé.
À šýñçĥŕöñîžéđ ƒöļđéŕ îš ŕéƒüšéđ
workspace.CloudSyncedDir ḿàţçĥéš à ŵöŕķšþàçé ŕööţ à þàţĥ šéĝḿéñţ àţ à ţîḿé,
çàšé-îñšéñšîţîṽéļý, àĝàîñšţ ţĥé ƒöļđéŕ ñàḿéš îÇļöüđ Đŕîṽé, Đŕöþƃöẋ, ÖñéĐŕîṽé àñđ
Ĝööĝļé Đŕîṽé üšé. À þŕéƒîẋ ḿàţçĥ ĥàš ţö éñđ àţ à šþàçé, à ĥýþĥéñ öŕ àñ
üñđéŕšçöŕé, šö OneDrive - Contoso ḿàţçĥéš àñđ OneDriveProjects đöéš ñöţ. Ţĥé
ḿéššàĝé ñàḿéš ţĥé ƒöļđéŕ, ţĥé þŕöđüçţ àñđ ţĥé ŵàý öüţ, ŵĥîçĥ îš ţö šéţ
KAPI_DATA_DIR ţö à đîŕéçţöŕý öüţšîđé îţ.
Àđöþţîöñ öüţ öƒ ţĥé éḿƃéđđéđ ļàýöüţ
projectdb.Open àšķš ŵĥéţĥéŕ ţĥé çöñţéẋţ šţöŕé ĥöļđš àñý üšéŕ ţàƃļé àţ àļļ
ƃéƒöŕé îţ ƃîñđš ţĥé šüƃšýšţéḿš, ƃéçàüšé ƃîñđîñĝ çŕéàţéš ţĥöšé ţàƃļéš. À ŵöŕķšþàçé
šüþþļîéđ ŵîţĥ àñ éḿþţý çöñţéẋţ šţöŕé àñđ à þŕöĵéçţîöñ ţĥàţ šţîļļ çàŕŕîéš çöñţéẋţ
ţàƃļéš îš àđöþţéđ.
Éṽéŕý çöñţéẋţ ŕöŵ ḿöṽéš, ƃéçàüšé ñöţĥîñĝ ŕéþŕöđüçéš öñé: ţĥé ţéŕḿš, ţĥé çöñţéñţ ḿéḿöŕý, ţĥé ṽöîçé þŕöƒîļéš àñđ éṽéŕý ŕéçöŕđ îñ ţĥé đéçîšîöñ ļéđĝéŕ àŕé ŕéàđ öüţ öƒ ţĥé öļđ šţöŕé àñđ ŕéçöŕđéđ îñ ţĥé ñéŵ öñé. Ţĥé öļđ šţöŕé'š öŵñ ḿîĝŕàţîöñ ŕüñš ƒîŕšţ, šö à þŕöĵéçţ ţĥàţ þŕéđàţéš ţĥé ļéđĝéŕ ĥàš îţš ŕöŵš çàŕŕîéđ îñţö öñé ƃéƒöŕé ţĥéý àŕé ŕéàđ.
Ŵĥàţ îš đŕöþþéđ àƒţéŕŵàŕđš îš çöḿþüţéđ ŕàţĥéŕ ţĥàñ ļîšţéđ. Àñ éḿþţý þŕöĵéçţîöñ îš
ƃüîļţ îñ ḿéḿöŕý, îţš ţàƃļéš àŕé ŵĥàţ à þŕöĵéçţîöñ îš éñţîţļéđ ţö ĥöļđ, àñđ éṽéŕý
öţĥéŕ ţàƃļé îñ ţĥé ƒîļé ƃéļöñĝéđ ţö à šüƃšýšţéḿ ţĥàţ ĥàš ḿöṽéđ öüţ. Ṽîŕţüàļ
ţàƃļéš àŕé đŕöþþéđ ƒîŕšţ, šîñçé ţĥéý ţàķé ţĥéîŕ šĥàđöŵ ţàƃļéš ŵîţĥ ţĥéḿ. Ţĥé
ŵĥöļé þàšš îš ƃéšţ-郃öŕţ: à þŕöĵéçţ ţĥàţ çàññöţ ƃé àđöþţéđ ķééþš ƃöţĥ çöþîéš àñđ
ŵöŕķš ƒŕöḿ ţĥé çöñţéẋţ šţöŕé, ŵĥîçĥ kapi store import ƒîļļš ƒŕöḿ ţĥé
çĥéçķöüţ'š öŵñ ƒîļéš.
Ŕéļàţéđ
- Ç-03: Ţĥé çöñţéẋţ šţöŕé àñđ ĝŕàþĥ: ţĥé đéçîšîöñ ţĥîš ñöţé îḿþļéḿéñţš.
- Ç-04: Ƃļöçķ šţàţé àñđ ţĥé đéçîšîöñ ŕéçöŕđ: ţĥé ļéđĝéŕ îñ ţĥé çöñţéẋţ þööļ.