Issue: Unexpected nQueryMode Values (21 and 0) in IOCP
Problem:
In the CDbManager :: PutThread function, an invalid nQueryMode is being passed, triggering the default case in the switch:
Hey There!
Please login and(or) register to see this awesome content today.
Hey There!
Please login and(or) register to see this awesome content today.
Why Are These Values Being Sent?
First, let’s understand what’s happening.
Windows IO Completion Port (IOCP) is used for efficient, asynchronous task handling across multiple threads. It lets the system manage threads waiting for IO operations to complete, helping to avoid the overhead of having too many threads or too many context switches. FlyFF utilizes this constantly to split tasks amongst threads to offload incoming network data in to a thread, or request that thread to handle a task. In this instance and most instances, it's to interact with the database to let the database post back.
- Connection Setup: Several CQuery objects are initialized to handle database connections
- Task Queueing: The PutThread() function enters an infinite loop where it calls GetQueuedCompletionStatus(), which blocks until an IO task completes or is posted to the IOCP.
- Task Handling: When a task is posted, GetQueuedCompletionStatus() returns a lpDbOverlappedPlus object that contains details about the completed task. Based on the task type (in nQueryMode), the thread executes the appropriate logic (e.g., saving concurrent user numbers to the database).
- Thread Management: IOCP allows multiple threads to wait on the same completion port, letting the OS distribute tasks efficiently. The tasks are processed as they complete, avoiding idle time in threads.
Example of Task Posting:
Here’s how tasks are posted:
Hey There!
Please login and(or) register to see this awesome content today.
It allocates memory for a task, make request copies the ar buffer, and it sets the query mode.
Conclusion
The error likely comes from incorrectly resetting or managing tasks, not IOCP itself. You’re likely sending tasks with unsupported nQueryMode values (e.g., 21 or 0) that aren’t handled. somewhere, you are sending those values in to g_DbManager.m_hIOCPPut and then there's nothing to handle it, giving your error.
Memory Usage Insights
The database server might sometimes use excessive RAM due to tasks piling up. For instance, saving a player involves allocating a new CMover on the heap, copying data, and posting it to the IOCP. If tasks aren’t handled efficiently, memory consumption increases. Here's an example of a potential memory-heavy scenario:
Ever wonder why the database server sometimes utilizes a lot of ram? While saving a player, the data that is sent over. A new CMover is allocated on heap, the data is copied in to and then that pointer is sent over as a task. These tasks can pile up and allocate way too much memory on heap. This is why constantly adding parameters to CMover affects the database to an extent and why there's rollback has to exist in most cases (good and bad).
You can see here there is an account cache system:
Hey There!
Please login and(or) register to see this awesome content today.
Hey There!
Please login and(or) register to see this awesome content today.
Here is save:
Hey There!
Please login and(or) register to see this awesome content today.
The connect to show the cache being used and intitialized with a new CMover as well:
Hey There!
Please login and(or) register to see this awesome content today.
(
Note: I believe v21.2 source removes the CMover cache)
As you can see, memory can start increasing per player saving and why original servers had the delay set longer. Not only that, but most servers now force call save on every action rather than letting the Save timer do it -- which is good for certain actions obviously like trading, to prevent dupes with unexpected server crashes -- but also adds more usage on the DBServer.