Skip to content

perf(seller): replace per-pick full auction-house scan with an O(1) duplicate tally - #165

Open
crazy-on-keyboard wants to merge 1 commit into
azerothcore:masterfrom
crazy-on-keyboard:perf/o1-duplicate-check
Open

crazy-on-keyboard wants to merge 1 commit into
azerothcore:masterfrom
crazy-on-keyboard:perf/o1-duplicate-check

Conversation

@crazy-on-keyboard

@crazy-on-keyboard crazy-on-keyboard commented Aug 29, 2026

Copy link
Copy Markdown

Changes Proposed:

  • Replace the seller's per-pick duplicate check — which re-scanned the entire auction map on every candidate item — with a per-item tally built once per Sell() cycle and looked up in O(1).
  • Behaviour is unchanged (same DuplicatesCount cap, counted per bot); only the duplicate-check implementation changes. No config, schema, or behavioural changes.

Why. AuctionHouseBot::getElement() enforces DuplicatesCount by re-scanning the whole AuctionHouseObject auction map on every candidate pick. Sell() picks up to ItemsPerCycle items per cycle and, when the low-rarity bins are duplicate-saturated, calls getElement() across all 14 rarity/type bins per pick — so per-cycle cost is roughly O(ItemsPerCycle × bins × auctions), i.e. it scales with the square of the auction-house size. On a single-thread-bound server (Ryzen 1700X) maintaining ~160k auctions this froze the world loop (Update time diff: 118345ms, CPU pegged, SOAP/logins unresponsive). The fix drops per-cycle cost from ~O(n²) to O(n).

Issues Addressed:

  • Severe world-loop stalls / freezes when the bot maintains a large auction house. (No existing issue linked.)

SOURCE:

  • Root cause is the for (... GetAuctionsBegin() ...) duplicate scan in getElement() (src/AuctionHouseBot.cpp), called once per candidate pick from Sell().

Tests Performed:

  • Builds without errors against AzerothCore (Linux / Docker).
  • Filled a 3-house auction house to ~147,000 auctions (DuplicatesCount = 2, all rarities present, ~39k rare/epic/legendary/artifact listings):
Before After
Fill ceiling before freeze ~100–160k 147k, stable
Worst world tick 118,345 ms (frozen) ~3.5 s transient during heaviest fill; most cycles none
SOAP / login during fill unresponsive responsive throughout (~140 ms)
  • Verified the duplicate cap still holds exactly (max copies per item per bot per house = DuplicatesCount).

How to Test the Changes:

  1. Configure the AH bot for a large auction house (e.g. AuctionHouseBot.DuplicatesCount = 2 and a high maxitems).
  2. Start the worldserver and let the bot fill the auction house.
  3. Watch the worldserver "Update time diff" while it fills — it stays low (no multi-second/minute stalls) and SOAP/logins remain responsive.

Summary by CodeRabbit

  • Bug Fixes
    • Improved auction item duplicate validation to consistently respect configured duplicate limits.
    • Prevented duplicate checks from becoming unnecessarily slow when processing multiple listings.
    • Duplicate counts now stay up to date as auctions are successfully added during each processing cycle.

…uplicate tally

The seller's DuplicatesCount check re-scanned the entire auction map on
every candidate pick. Since Sell() picks up to ItemsPerCycle items per
cycle and, when the low-rarity bins are duplicate-saturated, calls
getElement() across all 14 rarity/type bins per pick, the cost scaled
with roughly O(ItemsPerCycle * bins * auctions) -- i.e. with the square
of the auction-house size. On a single-thread-bound server this froze
the world loop on large auction houses (Update time diff up to 118s at
~160k auctions, CPU pegged, SOAP/logins unresponsive).

Build the per-item tally once per Sell() cycle into an unordered_map and
have getElement() do an O(1) lookup instead, keeping it in sync as
auctions are posted within the cycle. Behaviour is identical (same
DuplicatesCount cap, counted per bot); only the duplicate-check
implementation changes. Per-cycle cost drops from ~O(n^2) to O(n).
@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: aed0de95-d1e9-4a9c-a210-1e437a0c1e28

📥 Commits

Reviewing files that changed from the base of the PR and between a680cc1 and a0ff5a4.

📒 Files selected for processing (2)
  • src/AuctionHouseBot.cpp
  • src/AuctionHouseBot.h

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.


📝 Walkthrough

Walkthrough

The auction bot builds one per-cycle tally of its auctions when duplicate limits are enabled. Item selection uses this tally, and successful listings update it.

Changes

Auction duplicate tracking

Layer / File(s) Summary
Count-based duplicate selection
src/AuctionHouseBot.h, src/AuctionHouseBot.cpp
getElement now accepts a constant item-count map and validates duplicate limits with map lookup.
Listing-cycle tally integration
src/AuctionHouseBot.cpp
Sell builds the tally, passes it to item selections, and increments the listed item count after each successful auction.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to a0ff5

This change replaces an expensive duplicate-count scan with a per-cycle tally while preserving the duplicate cap and has no identified correctness or deployment risk; no actionable merge-blocking risk remains after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant Sell
  participant AuctionHouse
  participant getElement
  Sell->>AuctionHouse: read bot auction counts
  Sell->>getElement: pass shared item counts
  getElement-->>Sell: return eligible item
  Sell->>AuctionHouse: create auction
  Sell->>Sell: increment listed item count
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description covers the proposed changes, issue addressed, source, build and stress tests, results, and testing steps. It is complete and directly related to the pull request.
Title check ✅ Passed The title clearly and concisely describes the main performance change: replacing per-pick full auction-house scans with an O(1) duplicate tally.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

1 participant