-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(Core/AuctionHouse): Rework auctionhouse search threading #20830
Conversation
Always update worker threads to prevent possible resource leaks on empty/idle servers Remove redundant SearchableAuctionEntry list from AuctionHouseSearcher
These changes, while good, aren't currently necessary. Restore back to original to limit scope of PR. Will reimplement later with some changes.
and a little bit of misc refactoring to standardize some notation
Looks like this also closes #5068. |
Looks like I finally got most of the build check issues resolved, only problem remaining appears to be a couple small compatibility issues with ahbot, in which it'd probably be best just to update the ahbot module. |
Thanks for the update, could you please also prepare a PR for ahbot? Then we could get both merged when everything's ready :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you already know that I love this implementation 😁 I just have a few small nitpicks (some of them related to the old code).
src/server/game/World/World.cpp
Outdated
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update expired auctions")); | ||
sAuctionMgr->Update(diff); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we still need to put this code in an anonymous scope to measure the metric correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. 6cb4d9c
|
||
AuctionSearcherResponse* searchResponse = new AuctionSearcherResponse(); | ||
searchResponse->playerGuid = searchBidderListRequest.ownerGuid; | ||
searchResponse->packet.Initialize(SMSG_AUCTION_BIDDER_LIST_RESULT, (4 + 4 + 4) + 30000); // pussywizard: ensure there is enough memory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that this change (upfront allocation of 30 012 bytes) doesn't come from your side, but does it make sense to you? I thought the average bidder list shouldn't be that long.
On the other hand, I think upfront allocation can be useful for getAll requests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did see that but opted to not change it at the time, but yes, it's a bit excessive and ultimately useless. At 148 bytes per auction entry it's effectively preallocating the buffer size for ~202 bidder auction entries which is unlikely to be the case 99% of the time. It's a bit insane to pre-optimize for ultra edge cases especially when the optimization is overall extremely insignificant. Also, we don't do the same for either SMSG_AUCTION_OWNER_LIST_RESULT or SMSG_AUCTION_LIST_RESULT. As such, I have now removed it ed83ecd
{ | ||
for (auto const& pair : auctionMap) | ||
auctionEntries.push_back(pair.second.get()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nitpick: if we add return
here, we can get rid of the else
statement below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. f2e9608
else | ||
{ | ||
CreatureData const* auctioneerData = sObjectMgr->GetCreatureData(creature->GetSpawnId()); | ||
if (!auctioneerData) | ||
{ | ||
LOG_ERROR("network.opcode", "Data for auctioneer not found ({})", auctioneer.ToString()); | ||
delete AH; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
const Milliseconds delay = 2s; | ||
const Milliseconds now = GameTime::GetGameTimeMS(); | ||
Milliseconds diff = GetMSTimeDiff(_lastAuctionListItemsMSTime, now); | ||
if (diff > delay) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking maybe we could add rate limiter for some auction house opcodes somewhere here. What do you think? Maybe we can address it in a separate PR if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The auction list opcodes definitely should be throttled, in fact there's even a blizzlike client side delay that we add to the list packets (now defined as AUCTION_SEARCH_DELAY) but that's obviously only on the client side. Personally, I've seen the antidos system and I can't say I'm a huge fan of how it works for a variety of reasons that would take too long to elaborate on, but I suppose it's the best we have for now. It could still use some refinement if we had a better system but as a temporary measure I've added them 2a51d56
CMSG_AUCTION_LIST_ITEMS is still lacking the blizzlike throttle for "getAll" requests (something around ~15 minutes if I recall correctly?). I don't believe it to be too important at the moment but it should also be implemented at some point. (Note: If someone other than me eventually implements it, there's a "gotcha" that CMSG_AUCTION_LIST_ITEMS is currently handled as PROCESS_THREADSAFE, any global containers used in the handler must be locked or the opcode moved to PROCESS_THREADUNSAFE)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, agree. Thanks for addressing the comments!
@Takenbacon just so I know if i need to update the labels. Is this ready to be tested or still being changed/developed? |
Ready to be tested, nothing left on my end except for any requested changes during reviews/testing that may come up. |
I ran a small smoke test - no issues were found. |
Why use std::wstring instead string ? Most of the core manipulate char and not wchar_t. Even with OS differences, that shouldn't be an issue ? Does I'm wrong ? |
Mostly because that is what was there in the original implementation. Use of a wide string is not new from this PR.
Now, why we use a wide string in general? It's going to be for supporting the various languages/character encoding inputs received from the client. But, I couldn't really give you the specifics and I can't say I've bothered to really look into it. Character encoding is not a particular strong suit of mine as it is a confusing mess and varies significantly. You'll notice |
Please check the merge conflicts |
Conflicts resolved. |
Awesome sauce |
https://github.com/azerothcore/mod-eluna needs an update |
…hreading (azerothcore#20830)"" This reverts commit e2b2b13.
Complete rework of the auctionhouse search threading as the old system has been proven to be obviously very unsafe (#20538).
Simple model, spawns a configurable number of worker threads that each contain a pointer to a shared copy of AuctionEntry with an almost completely decoupled data structure (except for a pointer to ItemTemplate, which will be fine as long as we don't actively invalidate ItemTemplate data during run time. This can be "fixed" if needed by copying relevant item template data at the cost of increased memory usage and inability to modify existing data).
Scales well and is safe. I have used a similar model on servers with xx,xxx+ players and 150k+ auctions, however the implementation is quite different. I have done some initial local testing but I would highly recommend more testing before any merging. No danger to auctionhouse item data integrity during as we do not modify any auction entry data. Compile tested using MSVC only currently, GCC/Clang untested.
The auctionhouse system itself could use more changes but I kept the scope of this PR limited to just the searches.
Changes Proposed:
This PR proposes changes to:
Issues Addressed:
SOURCE:
The changes have been validated through:
Tests Performed:
This PR has been:
How to Test the Changes:
Known Issues and TODO List:
None currently.
How to Test AzerothCore PRs
When a PR is ready to be tested, it will be marked as [WAITING TO BE TESTED].
You can help by testing PRs and writing your feedback here on the PR's page on GitHub. Follow the instructions here:
http://www.azerothcore.org/wiki/How-to-test-a-PR
REMEMBER: when testing a PR that changes something generic (i.e. a part of code that handles more than one specific thing), the tester should not only check that the PR does its job (e.g. fixing spell XXX) but especially check that the PR does not cause any regression (i.e. introducing new bugs).
For example: if a PR fixes spell X by changing a part of code that handles spells X, Y, and Z, we should not only test X, but we should test Y and Z as well.