Skip to content

fix(amuleweb): clear search results across cycles + on new search (#31) - #33

Merged
got3nks merged 2 commits into
amule-org:masterfrom
got3nks:fix/amuleweb-search-results-partial-update
Jun 9, 2026
Merged

fix(amuleweb): clear search results across cycles + on new search (#31)#33
got3nks merged 2 commits into
amule-org:masterfrom
got3nks:fix/amuleweb-search-results-partial-update

Conversation

@got3nks

@got3nks got3nks commented Jun 9, 2026

Copy link
Copy Markdown

Summary

Fixes #31 — amuleweb's search results grow on every "Update results" click and don't clear when a new search starts. Two independent bugs, both contributing:

Bug 1 — SearchFile ECID was never forwarded from the tag (latent forever)

SearchFile(CEC_SearchFile_Tag *tag) never calls : CECID(tag->ID()). The default CECID() constructor auto-increments a static counter, so every SearchFile instance ends up with a local counter as its ID — completely disconnected from the daemon's ECID the tag carries. Sibling SharedFile / DownloadFile / UploadFile all forward correctly; SearchFile alone was left with the default ctor.

Consequence: m_items_hash.count(tag->ID()) always returns 0, every poll treats every result as new, ProcessFull re-appends each item — visible to the user as the result list growing on every "Update results" click.

Latent since the file was written. The pre-partial-update bulk "missing-from-reply == deleted" loop happened to wipe the list every cycle, so duplicates got rebuilt rather than accumulating. ee1d92b (EC skip-unchanged 5/5) made that loop conditional on m_partialUpdateActive, and the bug surfaced.

Bug 2 — daemon never emitted EC_TAG_FILE_REMOVED tombstones for search results

Get_EC_Response_GetSharedFiles and Get_EC_Response_GetDownloadQueue got partial-update tombstoning in ee1d92b. Get_EC_Response_Search_Results was missed. Once partial-update is negotiated, amuleweb's UpdatableItemsContainer::ProcessUpdate expects explicit EC_TAG_FILE_REMOVED markers and skips its legacy bulk-delete; without them, items from previous searches linger forever.

Bug 1 is a prerequisite for Bug 2's fix: tombstones carry daemon ECIDs, and without the SearchFile ECID forwarding, m_items_hash.erase(ecid) would have never matched.

Fix

Two commits:

  • fix(ec): emit EC_TAG_FILE_REMOVED tombstones on EC_OP_SEARCH_RESULTS — daemon-side. New per-session m_lastSentSearchIds on CECServerSocket; snapshot current search-result ECIDs each poll, emit one tombstone per ID that disappeared. Gated identically to the shared/download handlers (m_partialUpdateActive && detail_level == EC_DETAIL_UPDATE && queryitems.empty()).
  • fix(amuleweb): initialize SearchFile ECID from daemon tag — client-side. One line: SearchFile::SearchFile(...) : CECID(tag->ID()).

Backward compatibility

No protocol change.

The tombstone gate skips amulegui (different EC_DETAIL_LEVEL → different daemon overload), amulecmd (EC_DETAIL_FULL / EC_DETAIL_CMD), and amuleweb's Phase-3 follow-up (EC_DETAIL_FULL default from the single-arg CECPacket ctor). Old amuleweb against new daemon is unchanged — old client doesn't negotiate the protocol → gate off.

The SearchFile ctor fix is a pure client-side correction with no protocol effect.

Test plan

  • amuleweb against self-built amuled from this branch on a Linux amule-dev VM
    • Kad search "ubuntu 24.04" min size 4 GB → click "Update results" several times → result count stable, no duplicates
    • Start a new search → previous results disappear

Commit ee1d92b wired the partial-update protocol's skip-unchanged
+ EC_TAG_FILE_REMOVED logic into the daemon's shared-files and
download-queue handlers, and amuleweb's shared `UpdatableItemsContainer
::ProcessUpdate` learned to expect explicit deletion markers whenever
the negotiated capability was active.

`SearchInfo` inherits the same `ProcessUpdate` template body, but
`Get_EC_Response_Search_Results` was never extended to emit those
markers. The result is that on any 3.0.0 amuleweb against a 3.0.0
amuled, search results monotonically accumulate: a new search clears
the daemon's searchlist but the next `EC_OP_SEARCH_RESULTS` reply just
lists the new search's items with no tombstones for the old ones, so
the client never drops them (amule-project#31).

Add per-session `m_lastSentSearchIds` to CECServerSocket, snapshot the
current search-result ECIDs on each poll, emit one EC_TAG_FILE_REMOVED
per ID that was in the previous reply but is no longer in the
searchlist, then swap the snapshot in. Gate symmetrically with the
shared/download handlers — only `EC_DETAIL_UPDATE` polling from a
partial-update-capable client, and only when no `queryitems` subset
is specified, so amulegui's `EC_DETAIL_INC_UPDATE` overload,
amulecmd's `EC_DETAIL_FULL` one-shots, and amuleweb's Phase-3
follow-up (`req_full`, defaults to `EC_DETAIL_FULL`) are untouched.

Pure server-side fix; no client change needed: amuleweb's existing
`UpdatableItemsContainer::ProcessUpdate` already drains
`EC_TAG_FILE_REMOVED` from the reply.
@got3nks
got3nks marked this pull request as draft June 9, 2026 08:53
…ect#31)

SearchFile's constructor never forwards `tag->ID()` to its `CECID`
base, so every instance gets a fresh local counter from
`CECID::CECID()` instead of the daemon's ECID. Sibling
SharedFile / DownloadFile / UploadFile all do this correctly:

    SharedFile::SharedFile(CEC_SharedFile_Tag *tag) : CECID(tag->ID())

SearchFile alone was left with the default constructor.

Consequence: amuleweb's `m_items_hash` (keyed by SearchFile::ID()
= local counter) can never match `tag->ID()` (= daemon ECID) on
incoming updates. Every `UpdatableItemsContainer::ProcessUpdate`
cycle treats every result as new, queues every ID into the Phase-3
follow-up, and `ProcessFull` appends each item again -- visible to
the user as the result list growing on every "Update results" click.

Latent since the file was written: the bulk "missing-from-reply ==
deleted" loop in pre-partial-update ProcessUpdate happened to wipe
the list every cycle, so duplicates got rebuilt rather than
accumulating. ee1d92b (EC skip-unchanged 5/5) made that loop
conditional on `m_partialUpdateActive`, and the bug surfaced.

Also a prerequisite for the EC_TAG_FILE_REMOVED tombstoning in
this PR's previous commit: tombstones carry daemon ECIDs; with
the local counter, `m_items_hash.erase(daemon_ecid)` would have
never matched anything.
@got3nks got3nks changed the title fix(ec): emit EC_TAG_FILE_REMOVED tombstones on EC_OP_SEARCH_RESULTS fix(amuleweb): clear search results across cycles + on new search (#31) Jun 9, 2026
@got3nks
got3nks marked this pull request as ready for review June 9, 2026 09:34
@got3nks
got3nks merged commit 843bd12 into amule-org:master Jun 9, 2026
9 checks passed
@got3nks
got3nks deleted the fix/amuleweb-search-results-partial-update branch June 9, 2026 09:34
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.

amuleweb search duplicates results

1 participant