Smart chunk management
#1
Currently, our chunk management is bad. See #3142 for reference.
I have started fiddling around with various ways to manage this better (see #3151). I think we should discuss the optimal way to manage this. I explain the problem below. I also list the various proposals. The list may grow as we propose more ideas. Please discuss the various approaches. I need opinions on this.

Brief Background and Terminology
Minecraft is divided into chunks, they are saved in files. These chunks can either be loaded or unloaded. Loaded chunks reside RAM. When a player leaves a chunk, it should be unloaded at some point to free that RAM.

Dirty / clean chunks - Some chunks are dirty, meaning they changed since last saved to disk. These chunks must be saved to disk before being unloaded. Clean chunks have not changed since last saved and can simply be unloaded straight away.

Used / Unused chunks - Unused chunks are not being used by the game and have no players nearby, Assuming they are clean, we can unload them. Used chunks are being used by the game and must never be unloaded, whether dirty or clean. However, they should be periodically saved if dirty, to avoid data loss if the game crashes.

[Image: attachment.php?aid=707]
The problem
When a chunk becomes unused, we should unload it at some point. If we unload it too fast and a player gets back to it, we have wasted resources; the chunk must be re-loaded from disk into RAM. On the other hand, if we keep chunks too long, then server consumes too much RAM.

Solutions

The current approach (master branch)
Currently, Cuberite has a 10 second unload cycle and a 300 second save cycle.
  • Save cycle: All dirty chunks are saved, whether unused or used.
  • Unload cycle: All unused, clean chunks are unloaded.
Pros:
  • Simple code
Cons:
  • clean chunks are unloaded as soon as they're left. (This may be the way Vanilla does this, too)
  • Dirty chunks can persist in RAM for up to 5 minutes, until the save cycle arrives. Because dirty chunks cannot be unloaded before being saved. This can often overwhelm the ram of small devices. On Raspberry Pis, if you fly in a straight line too fast, you can choke the RAM.

The "Stable Ram" approach
This is the current approach in #3151.
  • A server has RAM dedicated for chunks, this is configurable in settings.ini
  • Unused, clean chunks are unloaded only when that RAM limit is exceeded.
  • If the RAM limit is exceeded but there are not enough unused clean chunks to unload, we resort to saving unused dirty chunks and then unloading them.
  • Additionally, there is a 300 second save cycle, so that chunks are never dirty for too long.
Pros:
  • Full RAM utilization, chunks are freed only when we have to.
  • Never overwhelms the server, the used RAM is static. Except in extreme cases where the amount of *used* chunks exceeds the configured RAM.
Cons:
  • The used RAM is static. This means that even when there are few players online, the server would be consuming the same amount of RAM as always.
  • The current chunk save scheme is random - we pick random unused chunks and free them. This can be improved in various ways.

Unload ASAP
Save and/or unload a chunk as soon as it becomes unused.
Pros:
  • Minimum RAM utilization, chunks are freed ASAP
  • Code already exists. Setting the RAM setting ridiculously low in the above solution does exactly this.
Cons:
  • Minimum RAM utilization and high disk usage. The RAM could have been better used.


Attached Files Thumbnail(s)
   
Reply
Thanks given by:
#2
I added a visual table.
Reply
Thanks given by:
#3
Can't we use a event based version of the current approach? Save or unload when a chunk is unused.
Reply
Thanks given by:
#4
(04-26-2016, 06:12 PM)NiLSPACE Wrote: Can't we use a event based version of the current approach? Save or unload when a chunk is unused.

That would be a simple solution which would minimize RAM usage, but chunks would be saved or unloaded too fast. For instance, you want to keep a chunk in RAM because a player may get back to it soon.

In the "Static RAM" branch, setting the RAM ridiculously low does exactly this, by the way.
Reply
Thanks given by:
#5
Added to the list.
Reply
Thanks given by:
#6
Perhaps instead of setting the amount of ram that Cuberite can use we set a minimum and a maximum. If possible Cuberite will use the minimum, but if it detects that we need more it uses more. That could prevent Cuberite using large amounts of RAM while only a few users are online.
Reply
Thanks given by:
#7
That could work. I've been thinking about the "if it detects" part. One way to do it would be this:
- A chunk is either bored or not bored.
- If a chunk is visited, it becomes not bored
- If a chunk is not visted for X ticks, it becomes bored.
- If there are too many bored chunks (e.g. more than half of loaded chunks), decrease max RAM until the amount of bored chunks is acceptable, or until the defined Minimum is reached,
- If there are too few bored chunks, Increase max RAM until the amount of bored chunks is acceptable, or until the defined maximum is reached.
Reply
Thanks given by:
#8
NiLSPACE: The stable RAM approach is closer to a minimum than a maximum at the moment. If the non-unloadable chunks require more memory than the ram limit, we will use it.

The ideal scenario is that cuberite uses exactly enough memory to fill RAM, without the system having to page either cuberite or any other application. For Dedicated servers, we can approximate this with the stable RAM approach, by setting the MAX to a significant proportion of RAM. For systems with other programs, cuberite would have to adjust its RAM in proportion to other applications requests. With the current saving architecture that is not achievable without OS support. So we have the options of the current/unload ASAP strategy. Both of these are focused primarily on minimizing our impact on other applications, and can leave significant amounts of memory unused. By comparison, The Stable RAM approach allocates a fixed amount of RAM as ours, and leaves the other applictions to the rest.
Reply
Thanks given by:
#9
On Windows one thing we can do, is use CreateMemoryResourceNotification to adjust our memory usage based on system memory usage. I'm also wondering if we could do a better approach to handling unloading chunks using memory mapped files.
Reply
Thanks given by:
#10
I do not think that any approach that adjusts the RAM used based on players is sensible. How much we should use is really a function of total ram, and how much other apps need. We can use as much as is available, but we don't want to be paged.
Reply
Thanks given by:




Users browsing this thread: 6 Guest(s)