Skip to content

SharedFileList: O(N²) → O(N log N) keyword indexing on Reload (#302) - #566

Merged
mrjimenez merged 1 commit into
amule-project:masterfrom
got3nks:feature/publishkeyword-map-index
May 11, 2026
Merged

SharedFileList: O(N²) → O(N log N) keyword indexing on Reload (#302)#566
mrjimenez merged 1 commit into
amule-project:masterfrom
got3nks:feature/publishkeyword-map-index

Conversation

@got3nks

@got3nks got3nks commented May 10, 2026

Copy link
Copy Markdown
Contributor

Summary

CPublishKeywordList::FindKeyword() did a linear scan of the keyword list on every call. AddKeyword() calls it once per keyword, and CSharedFileList::Reload() calls AddKeywords() once per shared file at startup — so the cost is O(N²) in the keyword set size. On a 10–100k shared library this lights one CPU core for minutes during init (backtrace from @mifritscher2 on #302).

Fix

Add a std::map<wxString, CKeyWordList::iterator> secondary index alongside the existing std::list. The list stays canonical — its insertion order is load-bearing for GetNextKeyword()'s round-robin publish cursor. The map is maintained in lockstep on every mutation site (AddKeyword, RemoveKeyword, RemoveAllKeywords, PurgeUnreferencedKeywords), so the iterators it stores stay valid with the list (std::list iterators are stable across other inserts/erases — only the erased iterator itself is invalidated).

FindKeyword now does a single map lookup, O(log N) — turning the startup hot path from O(N²) to O(N log N). For 100k keywords that's ~1.7M comparisons instead of ~10¹⁰.

Caveats

Independent from #560 / #561; addresses a separate hot spot on the same issue. Ordering is unchanged for the round-robin publish path, so no behavioural change at runtime.

…dKeyword (amule-project#302)

CPublishKeywordList::FindKeyword() did a linear scan of the keyword list
on every call. AddKeyword() calls FindKeyword() once per keyword, and
CSharedFileList::Reload() calls AddKeywords() once per shared file at
startup, so the cost is O(N²) in the keyword set size. With a 10–100k
shared library that lights one core for minutes during init (per the
backtrace in amule-project#302).

Add a std::map<wxString, list-iterator> secondary index alongside the
existing list. The list stays canonical (its insertion order is
load-bearing for GetNextKeyword()'s round-robin publish cursor); the
map is updated in lockstep on every mutation (Add/Remove/RemoveAll/
PurgeUnreferenced) so iterators in the map stay valid with the list.

FindKeyword now does a single map lookup — O(log N) — turning the
startup hot path from O(N²) to O(N log N). For 100k keywords that's
~1.7M comparisons instead of ~10^10.

Reported by @mifritscher2 on amule-project#302.
This was referenced May 10, 2026
@mifritscher2

Copy link
Copy Markdown

Wow, the fix was even more effective than I was prepared for debugging^^ The start time (start of amule until connected to a server) was dropped from ca. 20-30 minutes to about 3 min - the GUI being always responsive.

Thanks!

@mrjimenez
mrjimenez merged commit a779b30 into amule-project:master May 11, 2026
12 checks passed
@got3nks
got3nks deleted the feature/publishkeyword-map-index branch May 11, 2026 08:00
got3nks added a commit to got3nks/amule that referenced this pull request Jul 23, 2026
…-project#566)

Follow-up to amule-project#565: surface the memory-mapped file I/O preference on the REST
API. files.mmap_supported is a read-only daemon capability (mirrors
upnp_available), read from the EC_TAG_FILES_MMAP_SUPPORTED tag; files.mmap_enabled
is the runtime value. A PATCH that sets mmap_enabled is rejected with 409 when the
connected daemon lacks mmap support, so the option is only writable against a core
that can actually use it.

Updates docs/api/REFERENCE.md and the 15-preferences-patch curl smoke (round-trip
on a mmap-capable daemon; the 409 capability gate otherwise).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants