{{ message }}
enhance(import): optimize file graph import path - #13130
Open
tiensonqin wants to merge 56 commits into
Open
Conversation
tiensonqin
marked this pull request as ready for review
August 27, 2026 16:30
- Walk AST once per file; sync block tx for non-asset blocks - Track placeholder refs for scoped missing-ref cleanup - Add per-phase import profiling and optional 30s watchdog - Electron lazy file/asset read via fs-path descriptors - Integration test enables timeout without changing assertions Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Move export-doc-files before simple-page-property helpers so SCI/nbb can resolve it at runtime. Splice fast-path helpers from perf branch with paren fixes, content prefetch on partition fallback, and relaxed remove-inline-tags guard. Document that parallel doc import stays opt-in and off for db-worker. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Remove the simple-page-property fast path and direct-import machinery. Keep desktop lazy file reads and overlap the next file read with the current file's parse and transact via a read-ahead export-doc-files loop. Restore the large-graph integration test threshold to 25s. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Reintroduce the simple-page-property bulk import path (sqlite-build + build-direct-import-db) with single-pass batch accumulation instead of upfront file partitioning. Remove the read-ahead pipeline and pass :rpath-key through build-doc-options so the fast path can classify files. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Remove the simple-page-property / direct-import / read-ahead / atomic-batch machinery that did not improve docs-graph import (~15.8s) and regressed property-parent-classes validation. Keep the lean e57cb26 import path (AST walk once, sync block tx, desktop lazy read, watchdog) and make log-fn opt-in so imports stay quiet by default. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Prefix unused build-block-tx-core args and drop unused import-state binding. Revert graph-parser nbb-logseq specifier to git+https so frozen-lockfile CI matches pnpm-lock.yaml and other deps packages. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Extract file partition/steps and main-tx builders so export-file-graph and <add-file-to-db-graph stay under the 75-line limit. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Rebuild name->uuid from all pages on every file made movies import pages-tx grow with graph size. Index only pages saved from the current file. Skip search sync for imported txs. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Pre-seeding :page-names-to-uuids with journal file names made build-pages-tx treat those journals as already existing, so journal files skipped build-new-page-or-class and never wrote :block/title. Date properties then pointed at uuid-only placeholders and cleanup failed. Keep journals in :journal-page-name-uuids until the page is saved. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
The incremental name->uuid index reused a property uuid when a later file converted a same-titled tag to a class. That made :user.property/tag both a Property and a Tag on the docs graph. Keep properties out of :page-names-to-uuids so class lookup cannot collide with them. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
The incremental name index made a class titled tag look like an existing page, so tag:: converted that class into :user.property/tag. Keep the class and create a separate property entity instead. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Split unaccounted work in <add-file-to-db-graph> so parse, prep, pages-tx, split, prop-tx, clean-tags, main-tx, transact, and upstream can be measured independently when a log-fn is provided. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Add --profile/--profile-out to bb dev:import so markdown import is measured on the sqlite-backed CLI path used by Electron, including per-file phases and datascript sqlite -store time. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Set conn :skip-store? for export-file-graph, then d/store once. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
:block/name is indexed but not unique. Avoid scanning all uuids per tag. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Time d/with, store-after, listener callbacks, and block-refs rebuild separately from save-from-tx so a 400-file import can show where per-file transact time goes. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Time get-blocks-and-pages separately from db-rebuild-block-refs so per-file transact cost is not lumped into one listen bucket. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
mapcat was lazy, so rebuild cost leaked into ldb/transact!. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Skip per-file :block/refs rebuild on import txs. Stamp :block/tx-id and rebuild refs in one pass at the end of export-file-graph, matching Desktop finalize plus pipeline. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
nbb only sees existing ^:api outliner.pipeline vars. Rebuild the one-shot :block/refs pass in the exporter with db-rebuild-block-refs. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Outline parse is only for markdown files whose import is headings, properties, refs and tags. Render, editor, and import conversions that walk Src/Macro/Quote/Drawer AST keep mldoc full parse. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Outline parse leaves `template::` on the bullet line as title text, so empty-title template blocks never become #Template. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Property page refs already come from mldoc's drawer AST. Stop re-parsing every value with parseInlineJson during extract. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Pre-block refs already come from extract-properties drawer AST. Comma-separated plains use parseInlineJson instead of a full document parse. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Wire worker set-ui-state so import progress numbers update. Skip search index builds while a file-graph import is running, and skip the giant web finalize delta so reload stays responsive. Finalize still writes :block/refs on the worker so page refs and linked-reference counts survive after reload. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Cover worker conn refs, canonical-block, get-block-refs, published replacements, and import progress updates after file-graph import. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Outline parse drops quote body, including emails. Detect `- >` and numbered-list quotes so those files use full parse. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Calling done inside the import test finally raced restoring-worker-state cleanup and could wipe *main-thread for later search index tests. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
tiensonqin
force-pushed
the
logseq/optimize-markdown-import-d899
branch
from
August 31, 2026 14:13
2d13c26 to
b4ecc4e
Compare
File-graph import must not broadcast render deltas to any client; a large graph posts a giant Comlink payload and can crash after parse. Stamp remaining import transacts with imported-data, copy page-drawer refs onto the page, and restore the current desktop graph from the worker after import. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Do not return file contents, asset bytes, or the full import index through transit. Write assets in the worker, show the current file during import, and update later steps such as finishing and validating without dumping internals. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
File-graph import no longer transit-encodes the worker reply. The renderer reads a counts-only summary from UI state. The progress dialog opens immediately as Importing and graph create no longer redirects away. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Run the file-graph-import create-db assertions in the existing async with-redefs test so they do not race the default create path. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
File-graph import now notifies ignored-property counts only, so the per-property icon and type-mismatch strings are unused. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Create the DB graph first, then import. Desktop progress uses the node event channel, a single file failure continues the rest, and restore runs once without a page reload or a second search rebuild. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Keep p/with-redefs active until create-db promises settle so the next async test cannot restore the real persist-db/<new. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Electron already stops the previous db-worker-node when the window binds to the imported graph, but the renderer EventSource for that old port kept reconnecting. Mark the old session inactive, serialize runtime switches, and close native SSE handlers on disconnect. Also yield during finalize so Finishing can flush, skip worker recovery while import is running, and keep the imported graph if the invoke transport drops after files have finished. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Long import must keep the HTTP server from timing out, but writing the 200 headers before invoke finished forced every lock and validation failure onto HTTP 200. Send the real 409/400/500 after the handler returns, keep request/header timeouts disabled, and split request routing so make-server stays under the large-vars limit. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Header RTC uuid, left-sidebar class pulls, custom CSS/JS, and plugin graph-changed hooks no longer invoke the worker before it is initialized. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Stamp tx-id and rebuild refs in one transact instead of 500-entity batches. Accept a filesystem path in <get-file-stat so birthtime is imported. Return a small terminal contract from import-file-graph so the renderer does not race HTTP completion against SSE UI state. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Failed transact used to prn the full tx-data. On a large file-graph finalize that overflows Array.join, masks the original error, and can exit the Node worker. Log tx-count and rethrow the original error. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Keep-graph after a dropped import RPC no longer treats {} as a valid
import. Remove unused serialize/notification wrappers, leftover promise
wrapping around sync finalize, and unused electron-lazy SSE setup.
Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Finishing and last-file idx are set before sqlite store and refs finalize. Keep the new graph only after :validating. Treat only explicit transport codes as recoverable, not bare js/Error. Reject HTTP 200 replies without transit, rethrow lazy file-read failures, and log stat errors instead of swallowing them. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Remove stubbed transit encode/decode tests that no longer guard an import-specific path. Drop dead :graph/importing-result assertions. Cover Electron lazy descriptors and renderer notifications from a non-empty terminal result. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Keep the renderer import harness under the 100-line large-vars limit so CI lint can pass. Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Speeds up markdown file-graph import. Import stays sequential, one file at a time. Search indexes are not built during import.
The new DB graph is created before import. File-graph import does not broadcast renderer deltas to other clients. Assets are written in the worker.
The import indicator opens immediately as Importing. After files are written, it shows Finishing graph import and validating. Creating the empty graph no longer redirects away from that UI.
After import, page properties and
:block/refsare rebuilt in onefinalize-imported-graph!transact. The current client restores the graph from the worker on web and desktop. There is no full page reload. Search index rebuild runs once after restore.Desktop progress uses the db-worker-node event channel (
set-ui-stateover SSE), not the main-thread stub. A single file failure is recorded and skipped; later files still import.:thread-api/import-file-graphreturns a small terminal contract over the same RPC (:run-id,:status,:persisted?,:validation,:issue-count, plus compact counts). The renderer uses that RPC return value. HTTP 200 replies without a transit result fail instead of decoding asnil.File timestamps come from Node
fs.staton the path string the exporter already passed. Transact failures log:tx-countand the original error instead of printing full:tx-data. Lazy file-read failures are ignored as failed files, not imported as empty pages.If the desktop invoke drops after the worker has persisted the graph (
:validating), the new graph is kept. A drop during Finishing, or a plain transact/js/Errorwithout transport metadata, switches back to the previous graph.Test plan
frontend.components.imports-test(keep-graph only after:validating; finishing drop switches back; Electron lazy descriptors; terminal notifications),frontend.worker.db-core-testimport/transact-log/lazy-read cases,frontend.worker.db-worker-node-testfile-graph import cases,frontend.persist-db.remote-test(missingresultTransitrejects)encodes-terminal-result,decodes-terminal-result,:graph/importing-resultnegatives) were removedbb lint:large-varsstays under the 100-line limitls-movies-4kfrom logseq/db-benchmark-graphs completed in-process (~10 min) without Node crash; one-shot finalize persisted. Not added as a committed:longtest.Notes
PR is behind current
master. Import-related files should merge cleanly; rebase separately if desired.