Repository navigation
Conversation
When running semcode-index --lore to refresh existing mailing list archives, automatically clone and index any newly created shard repositories advertised in lore.kernel.org/manifest.js.gz instead of only printing a notification message. Factor the lore archive clone/index, table compaction/FTS optimization, new shard discovery, and superseded shard retirement logic into dedicated helper functions. To avoid deleting a superseded shard repository before its tail commits are completely fetched and indexed: - Check lore.kernel.org/manifest.js.gz and clone/index any new shards (<list>/<N>) before fetching and indexing existing shards (<list>/<M>). Because public-inbox v2 permanently seals shard M once shard N > M is created, fetching M after N is already visible in manifest.js.gz guarantees that M's fetch retrieves all of its final commits. - Track both inserted email count and recorded commit SHA count in process_lore_commits_pipeline, including public-inbox administrative deletion (rm) commits that contain file d without file m, so those commits are recorded in lore_indexed_commits and not retried on every run. - Only retire a superseded local shard directory (<list>/<M> where a higher shard <list>/<N> is present) once all shards for <list> are 100% indexed with no errors. Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
During bulk lore archive indexing, insert_lore_emails calls filter_existing_lore_ids on every 1,024-email batch. Previously, filter_existing_lore_ids executed a DataFusion SQL query with a 1,024-element IN clause against the unindexed lore LanceDB table on every batch. Because lore table compaction is deferred until the end of the indexing run, each batch triggered a parallel full-table scan across hundreds of uncompacted fragments, causing resident memory to spike to over 100 GB and consuming tens of minutes of CPU time. Replace the per-batch SQL IN scan with a lazily populated in-memory HashSet (lore_message_id_cache) on DatabaseManager: - On the first batch, stream only the message_id column from the lore table one RecordBatch at a time via try_next() so Arrow batch buffers are dropped immediately. - Update the cached set with newly inserted message_ids after each batch and clear the cache in compact_lore_tables(). - Also update get_indexed_lore_commits() to consume RecordBatches via try_next() instead of materializing all batches at once with try_collect(). Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
In process_lore_commits_pipeline, each of the num_workers threads previously opened its own gix::Repository instance and buffered up to batch_size (1,024) parsed LoreEmailInfo records locally before sending a batch to the database inserter. On high-core machines (e.g. 128 cores), workers pulled commits in round-robin fashion and accumulated up to num_workers * batch_size parsed emails in RAM simultaneously before flushing fragmented partial batches at EOF. Bound both in-flight memory and git packfile cache overhead: - Clamp git worker threads to at most 16, which easily saturates the single database inserter without opening 100+ separate gix::Repository packfile mappings and object caches. - Replace per-worker batch buffers with a bounded channel (batch_size * 2) feeding a single batch-collector thread that emits uniform batch_size batches into a 4-batch result channel. Signed-off-by: Dmitry Torokhov <dmitry.torokhov@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
lore.kernel.orgusespublic-inboxv2 repositories partitioned into numbered epoch shards (git/0.git,git/1.git, ...,git/N.git). When a shard reaches its size limit (~1 GB),lore.kernel.orgpermanently seals that shard and creates<N+1>.git(for example,lkml/git/20.gitsupersedinglkml/git/19.git).Previously,
semcode-index --lore(with no arguments) only rangit fetchon existing<db_path>/lore/<list_name>/<N>directories already present on disk. As a result:<N+1>.git,semcode-index --lorenever discovered or cloned the new shard and silently stopped receiving new emails for that list.<list>/<M>bare git repositories remained on disk indefinitely, even though all of their emails were already stored in the LanceDBloretable andgit fetchon them was a perpetual no-op.lore.message_idviatry_collect(), whilenum_cpus::get()worker threads (e.g., 128+ threads) simultaneously bufferednum_workers * batch_sizefull email bodies in RAM.This series fixes shard rollover discovery, retires superseded local git shards once verified complete, and reduces peak bulk-indexing memory on high-core-count workstations from ~103 GB to ~3.7 GB.
Changes
1.
semcode-index: automatically sync new lore shards and retire old oneslist_manifest_lore_archives,find_new_lore_archives,sync_new_lore_archives):list_manifest_lore_archives()to parse/<list_name>/git/<N>.gitentries fromhttps://lore.kernel.org/manifest.js.gzand share it betweenresolve_lore_url()andfind_new_lore_archives().semcode-index --lore(both standalone and combined refresh), checkmanifest.js.gzfor any shards<N>strictly greater than the highest local shard<max_local>for each tracked mailing list, and automatically clone and index them.retire_superseded_lore_archives):sync_new_lore_archives()before fetching and indexing existing local shards. Becausepublic-inboxv2 permanently seals shardMbefore publishing shardN > Minmanifest.js.gz, observingNinmanifest.js.gzbefore runninggit fetchonMguarantees thatM's fetch retrieves all of its final tail commits.fully_indexed == true(recorded_commits == new_count) with no fetch or indexing errors, remove the local bare git directories for superseded shards (< max_num) while keeping<max_num>on disk as the high-water mark. All indexed emails remain permanently stored in the LanceDBloretable.public-inboxDeletion Commits (LoreCommitParseOutcome::NoEmailFile):public-inboxdeletion (rm) commits (whose tree contains'd'instead of'm') by recording their commit SHAs inlore_indexed_commitswithout deleting existing rows fromlore, preventing them from remaining permanently unindexed and blocking shard retirement.'m'blob in a single pass (parse_email_from_blob_content) and filter failed insertions bymessage_idso duplicate-message_idcommits in a batch are never prematurely recorded inlore_indexed_commitson error.2.
database: cache lore message_ids in memory during bulk insertionmessage_ids inDatabaseManager::lore_message_id_cache(tokio::sync::Mutex<Option<HashSet<String>>>):message_idcolumn from theloretable oneRecordBatchat a time viatry_next()(dropping each Arrow buffer immediately instead of materializing all batches viatry_collect()).message_ids in the cached set under the mutex so concurrent inserter tasks (db_threads > 1) cannot insert duplicatemessage_ids across concurrent batches, and roll back anyfailed_indiceson insertion error.get_indexed_lore_commits()viatry_next()as well, and invalidatelore_message_id_cacheinclear_all_data(),compact_lore_tables(),drop_and_recreate_tables(), anddrop_and_recreate_table("lore").3.
indexer: bound in-flight memory and worker count in lore pipelineprocess_lore_commits_pipeline()tonum_workers.clamp(1, 16)so high-core-count machines do not spawn dozens of idle git pack-cache and parsing threads when bottlenecked on LanceDB writes.Vec<LoreEmailInfo>batch buffers (num_workers * batch_sizeemails held concurrently across worker threads) with a boundedmpsc::sync_channel(batch_size * 2)feeding a single batch collector thread and a boundedtokio::sync::mpsc::channel(4)feeding the async database inserters.tokio::task::spawn_blockingso Tokio executor threads remain free to drive the async inserter tasks.Testing & Verification
lkml/19(222,448 commits, includingpublic-inboxdeletion commits) followed bysemcode-index --loreautomatic discovery oflkml/20, tail catch-up, and automatic removal of the supersededlkml/19git clone directory.lkml/19->lkml/20rollover completed in ~20s.lore_search,dig) across emails from bothlkml/19andlkml/20.dtor@dtor-ws:~/kernel/linux-next (b4/geode-swnode)$