Level: Only register generators when attempting to actually generate chunks

This saves a ton of memory on servers which don't generate any chunks during their runtime (which is most servers).
This commit is contained in:
Dylan K. Taylor 2018-07-14 11:34:55 +01:00
parent fe7ad7a5b3
commit 53068caf3c
2 changed files with 31 additions and 18 deletions

View File

@ -200,6 +200,8 @@ class Level implements ChunkManager, Metadatable{
private $chunkPopulationLock = [];
/** @var int */
private $chunkPopulationQueueSize = 2;
/** @var bool[] */
private $generatorRegisteredWorkers = [];
/** @var bool */
private $autoSave = true;
@ -245,9 +247,6 @@ class Level implements ChunkManager, Metadatable{
/** @var bool */
private $closed = false;
/** @var \Closure */
private $asyncPoolStartHook;
public static function chunkHash(int $x, int $z) : int{
return (($x & 0xFFFFFFFF) << 32) | ($z & 0xFFFFFFFF);
}
@ -363,10 +362,6 @@ class Level implements ChunkManager, Metadatable{
$this->temporalPosition = new Position(0, 0, 0, $this);
$this->temporalVector = new Vector3(0, 0, 0);
$this->tickRate = 1;
$this->server->getAsyncPool()->addWorkerStartHook($this->asyncPoolStartHook = function(int $worker) : void{
$this->registerGeneratorToWorker($worker);
});
}
public function getTickRate() : int{
@ -382,15 +377,16 @@ class Level implements ChunkManager, Metadatable{
}
public function registerGeneratorToWorker(int $worker) : void{
$this->generatorRegisteredWorkers[$worker] = true;
$this->server->getAsyncPool()->submitTaskToWorker(new GeneratorRegisterTask($this, $this->generator, $this->provider->getGeneratorOptions()), $worker);
}
public function unregisterGenerator(){
$pool = $this->server->getAsyncPool();
$pool->removeWorkerStartHook($this->asyncPoolStartHook);
foreach($pool->getRunningWorkers() as $i){
foreach($this->generatorRegisteredWorkers as $i => $bool){
$pool->submitTaskToWorker(new GeneratorUnregisterTask($this), $i);
}
$this->generatorRegisteredWorkers = [];
}
public function getBlockMetadata() : BlockMetadataStore{
@ -2955,7 +2951,11 @@ class Level implements ChunkManager, Metadatable{
}
}
$task = new PopulationTask($this, $chunk);
$this->server->getAsyncPool()->submitTask($task);
$workerId = $this->server->getAsyncPool()->selectWorker();
if(!isset($this->generatorRegisteredWorkers[$workerId])){
$this->registerGeneratorToWorker($workerId);
}
$this->server->getAsyncPool()->submitTaskToWorker($task, $workerId);
}
}

View File

@ -168,18 +168,15 @@ class AsyncPool{
}
/**
* Submits an AsyncTask to the worker with the least load. If all workers are busy and the pool is not full, a new
* worker may be started.
* Selects a worker ID to run a task.
*
* @param AsyncTask $task
* - if an idle worker is found, it will be selected
* - else, if the worker pool is not full, a new worker will be selected
* - else, the worker with the smallest backlog is chosen.
*
* @return int
*/
public function submitTask(AsyncTask $task) : int{
if($task->getTaskId() !== null){
throw new \InvalidArgumentException("Cannot submit the same AsyncTask instance more than once");
}
public function selectWorker() : int{
$worker = null;
$minUsage = PHP_INT_MAX;
foreach($this->workerUsage as $i => $usage){
@ -202,7 +199,23 @@ class AsyncPool{
}
assert($worker !== null);
return $worker;
}
/**
* Submits an AsyncTask to the worker with the least load. If all workers are busy and the pool is not full, a new
* worker may be started.
*
* @param AsyncTask $task
*
* @return int
*/
public function submitTask(AsyncTask $task) : int{
if($task->getTaskId() !== null){
throw new \InvalidArgumentException("Cannot submit the same AsyncTask instance more than once");
}
$worker = $this->selectWorker();
$this->submitTaskToWorker($task, $worker);
return $worker;
}