• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Why is the first login of a character slower ?

gudan garam

Advanced OT User
Joined
Feb 13, 2011
Messages
353
Solutions
17
Reaction score
173
Location
São Paulo.
So I'm trying out ways of removing the freezes when someone leaves a house with too much items, caused by the items being moved from house to player's inbox and than saving it in database.

And I came to find that the first login of a player is faster than the subsequent ones.

It is probably cache but how does that work? If a player logout shouldn't their items be gone from memory?

The loading time is always 10x faster on the subsequent logins.
Example:

Code:
[IOLoginData::loadPlayer] exec time: 0.121 seconds.
Community Manager has logged in.
Community Manager has logged out.
[IOLoginData::loadPlayer] exec time: 0.022 seconds.
Community Manager has logged in.
Community Manager has logged out.
[IOLoginData::loadPlayer] exec time: 0.021 seconds.
Community Manager has logged in.
Community Manager has logged out.

How is the memory managed here? Is there a delay to delete that players stats from memory intentionally or is that default?
 
Long explanation in spoilers. short explanation after.

When a program asks for a piece of data, for example a player's information, the loading time depends on where the data is located - I'll link a table in the end.

When you first launch your server, all player data and account data is in the database, which means the disk (be it an SSD or HD or perhaps a flash memory, if you run the server from an USB stick).
The first time the server requests to load the player's data, it has to be read from the disk, which takes something of the order of 20,000,000ns. The data is then moved to the RAM, also known as main memory, and a copy will be moved to the cache. Any access when the data is already in the L1 cache will take 0.5ns. If it is in the RAM, expect 100ns to load the data. Pretty fast right?

However, the cache and the memory tend to be small, and the system has a policy to remove data from caches and RAM that are built in either in the operating system or on the hardware itself, merely because they get full.
For example, the system can keep track of how long it has been since every data entry in the cache has been accessed. Should the cache get full, it discards the least used data. The same thing happens in different stages, but with different policy.
Let's assume a "player" uses 10KB of data. A typycal L1 cache contains 64KB of data, meaning it can load 6 entire players until it has to replace an entry. Of course, your server has to deal with all types of data, not only players, which means at any given point the cache will contain monsters, NPCs, map, network, database and all sorts of data. But the player will still be faster to access than the first time because it is in the RAM. Loading from there is much faster than loading from the disk.
Table with loading times:
https://gist.githubusercontent.com/...173d0b59820f63cc6d489ec4f449bc126/latency.txt

Anyways, back to your question, in line 1 you can see the player took 0.121 seconds to load, whereas on lines 4 and 7 it took 0.022/0.021. This is because the first time the player had to be read from the disk, and the other times from a faster memory, be it RAM or one of the caches.

To answer what you asked directly:
How is the memory managed here? Is there a delay to delete that players stats from memory intentionally or is that default?
The data entry will be deleted from cache when it becomes too full, and it will be removed from RAM when and if you use disk swap, which is not recommended.
Data not removed from memory will not make anything necessarialy slower other than the actual memory, depending on how it is implemented.
You can force clear the cache, how exactly depends on what operating system you're using. For linux instructions read this How to programmatically clear the filesystem memory cache in C++ on a Linux system?

It is probably cache but how does that work? If a player logout shouldn't their items be gone from memory?
Keeping players and accounts in memory is desireable because it reduces log in times.

So I'm trying out ways of removing the freezes when someone leaves a house with too much items, caused by the items being moved from house to player's inbox and than saving it in database.
The freeze is much more likely to be caused by a bottleneck in the algorithm - or even the whole way this event is controlled - rather than the memory in this case. You need to understand that the memory is inherently slow and avoid using memory as much as possible, let alone the disk. If you need to move huge chunks of memory around every time a player performs a certain action then you need to limit this action. It is just not possible. In your specific case, the player probably cannot abuse this by repeatedly performing the action. You have multiple options here, all with pros and cons:
  • Optimize the house -> inbox transfer as much as possible. If the problem is solved, great;
  • Limit how many items will be moved to inbox to a fixed, treatable amount. Warn players about this limit. When the player leaves the house, delete everything above this limit;
  • Instead of saving it imediatelly to the database, consider other approaches, such as keeping it in memory for a certain time and scheduling the save for another less busy time when the server is either less probable to freeze or the freeze won't affect the players (server save, for example);
  • You could consider saving the items in chunks as opposed to all at once. This has to be analyzed carefully though.
 
Thanks for the answer, I highly appreciate both long and short explanation, really do.

Talking about the options you pointed:

1) This would probably not be thaaat effective, considering this comment: Lag from excessive items in containers [$10] · Issue #1150 · otland/forgottenserver (basically, we can make it move 100000 items in 0.1s but the player will try to put 1 billion items and freeze it again). And the method that does this right now, is not the bottleneck (I think).

2) This is the easiest way in my opinion, but I'm not comfortable with it, yet.

The last two are the ones I'd like to think about (the last one being my favorite tbh):

3) This is a bit risky, I actually don't know how to keep the items in memory, what would I keep, broad question, I know, but let's say a player just used !leavehouse, so x items are now stored in memory (what would this be? a vector of copies of the items? pointers? I dont really know this part), they also went to his inbox, so imagine if he goes and grab some of that items that went from his house to his inbox, I'd have change the items stored before aswell, how would I do that?
I know the items are already stored in memory and I can access it using the players inbox, but what if the player logs out, its not saved in db yet, and the reference is gone so are the items. Can I check on login if I have something of that player in memory? idk.

4) This is, imo, the best option, meaning its not that hard to implement and will, I think, solve the freezes, since "moving the items in game" isn't really that slow. Why do you think this has to be analyzed that carefully? Anythin special?

Now, thinking about 3 and 4 together, that would be awesome. Being able to save those items in memory is the hard part to me, I don't understand how to keep track of that. And than, on server save, save those items in smaller queries, if needed.

Expanding thoughts, I could proccess leavehouse requests at server saves, now I don't have to move items ingame (option 1 is not needed anymore) and I'd just have to split the items into smaller portions if its a huge amount, for the insert queries.


What do you think?
 
Thanks for the answer, I highly appreciate both long and short explanation, really do.

Talking about the options you pointed:

1) This would probably not be thaaat effective, considering this comment: Lag from excessive items in containers [$10] · Issue #1150 · otland/forgottenserver (basically, we can make it move 100000 items in 0.1s but the player will try to put 1 billion items and freeze it again). And the method that does this right now, is not the bottleneck (I think).

2) This is the easiest way in my opinion, but I'm not comfortable with it, yet.

The last two are the ones I'd like to think about (the last one being my favorite tbh):

3) This is a bit risky, I actually don't know how to keep the items in memory, what would I keep, broad question, I know, but let's say a player just used !leavehouse, so x items are now stored in memory (what would this be? a vector of copies of the items? pointers? I dont really know this part), they also went to his inbox, so imagine if he goes and grab some of that items that went from his house to his inbox, I'd have change the items stored before aswell, how would I do that?
I know the items are already stored in memory and I can access it using the players inbox, but what if the player logs out, its not saved in db yet, and the reference is gone so are the items. Can I check on login if I have something of that player in memory? idk.

4) This is, imo, the best option, meaning its not that hard to implement and will, I think, solve the freezes, since "moving the items in game" isn't really that slow. Why do you think this has to be analyzed that carefully? Anythin special?

Now, thinking about 3 and 4 together, that would be awesome. Being able to save those items in memory is the hard part to me, I don't understand how to keep track of that. And than, on server save, save those items in smaller queries, if needed.

Expanding thoughts, I could proccess leavehouse requests at server saves, now I don't have to move items ingame (option 1 is not needed anymore) and I'd just have to split the items into smaller portions if its a huge amount, for the insert queries.


What do you think?
I believe the third solution is the best one. The items are already in memory when they are in a house, so moving them elsewhere would use the same space. The major risk is the server crashing before you had the opportunity to save them to database.
Talking more about how this would be implemented, you could create a table where the key is the player and the value is a vector of items. Whenever a player leaves their house all item is inserted to the vector and deleted from the house until the house is full. When the server is about to save, this table is processed completely, no matter how large it is, and upon login every player will find their items in the inbox. Allowing access to the items before the save would require it to be implemented as something else than a vector because removing an element from a vector can be very slow. These details have to be thoroughly considered when you get to the implementation.

The fourth option is difficult to design and implement. The difference between 3 and 4 is that in 3 all items are saved at once during server save, and in 4 you must come up with a load balancing scheme to make sure this still doesn't interfere. If you decide you'll split a save of 1.000.000 items in 1.000 chunks of 1.000 items, for example, and you decide you'll save one chunk every 0.1 seconds, this means that for 100 seconds you'll have hard work being done by the server. Is it something you're willing to deal with? While freezes are less likely, there is a possibility your server will run slower for a long time depending on the chunk size and the frequency of saves.
 
Back
Top