Compare commits

...

9 Commits

Author SHA1 Message Date
1ff6f8846e disable dev flag 2018-08-04 16:30:23 +01:00
87f458f9bd AsyncPool: remove now-unnecessary isTerminated() call 2018-08-03 20:07:37 +01:00
5a7e575c3a AsyncPool: isCrashed() now returns true when a fatal error occurred
the fix for chunks earlier didn't fix...
2018-08-03 20:06:41 +01:00
d6d98183ea MainLogger: Log messages and exception traces in a synchronized block
this ensures that stack traces are emitted coherently without messages from other threads landing in the middle.
2018-08-03 18:50:06 +01:00
9ff5c65fb6 Level: Make async chunk sending aware of faults
Previously any random error could occur during an AsyncTask preparing a chunk, and the Level would never know about it and thus never send the chunk.

I don't know how many invisible-chunk bug cases this fixes, but I expect it's quite a lot.
2018-08-03 18:23:32 +01:00
1532b0ef6d Level: Remove chunks from chunk send queue on unload
When a chunk request task crashes, these can get stuck and never get removed. This allows using /gc to collect the bad chunk in order to fix the bug.
2018-08-03 18:04:56 +01:00
9ece971a2b Server: remove useless check from exceptionHandler()
this cannot be null... @shoghicp y u litter the code with these useless checks ???
2018-08-02 14:41:28 +01:00
5546c88f88 Server: Fixed parse errors getting reported to CA
this changed to throwing errors as of PHP 7
2018-08-02 14:40:36 +01:00
e8c7ae595d back to dev 2018-07-30 15:08:32 +01:00
6 changed files with 48 additions and 45 deletions

View File

@ -37,7 +37,7 @@ namespace pocketmine {
use pocketmine\wizard\SetupWizard;
const NAME = "PocketMine-MP";
const BASE_VERSION = "3.0.9";
const BASE_VERSION = "3.0.10";
const IS_DEVELOPMENT_BUILD = false;
const BUILD_NUMBER = 0;

View File

@ -2144,10 +2144,6 @@ class Server{
* @param array|null $trace
*/
public function exceptionHandler(\Throwable $e, $trace = null){
if($e === null){
return;
}
global $lastError;
if($trace === null){
@ -2205,7 +2201,7 @@ class Server{
}
}
if($dump->getData()["error"]["type"] === "E_PARSE" or $dump->getData()["error"]["type"] === "E_COMPILE_ERROR"){
if($dump->getData()["error"]["type"] === \ParseError::class){
$report = false;
}

View File

@ -191,7 +191,7 @@ class Level implements ChunkManager, Metadatable{
/** @var Player[][] */
private $chunkSendQueue = [];
/** @var bool[] */
/** @var ChunkRequestTask[] */
private $chunkSendTasks = [];
/** @var bool[] */
@ -2456,7 +2456,7 @@ class Level implements ChunkManager, Metadatable{
}
private function sendChunkFromCache(int $x, int $z){
if(isset($this->chunkSendTasks[$index = Level::chunkHash($x, $z)])){
if(isset($this->chunkSendQueue[$index = Level::chunkHash($x, $z)])){
foreach($this->chunkSendQueue[$index] as $player){
/** @var Player $player */
if($player->isConnected() and isset($player->usedChunks[$index])){
@ -2464,7 +2464,6 @@ class Level implements ChunkManager, Metadatable{
}
}
unset($this->chunkSendQueue[$index]);
unset($this->chunkSendTasks[$index]);
}
}
@ -2473,11 +2472,17 @@ class Level implements ChunkManager, Metadatable{
$this->timings->syncChunkSendTimer->startTiming();
foreach($this->chunkSendQueue as $index => $players){
if(isset($this->chunkSendTasks[$index])){
continue;
}
Level::getXZ($index, $x, $z);
$this->chunkSendTasks[$index] = true;
if(isset($this->chunkSendTasks[$index])){
if($this->chunkSendTasks[$index]->isCrashed()){
unset($this->chunkSendTasks[$index]);
$this->server->getLogger()->error("Failed to prepare chunk $x $z for sending, retrying");
}else{
//Not ready for sending yet
continue;
}
}
if(isset($this->chunkCache[$index])){
$this->sendChunkFromCache($x, $z);
continue;
@ -2490,7 +2495,8 @@ class Level implements ChunkManager, Metadatable{
}
assert($chunk->getX() === $x and $chunk->getZ() === $z, "Chunk coordinate mismatch: expected $x $z, but chunk has coordinates " . $chunk->getX() . " " . $chunk->getZ() . ", did you forget to clone a chunk before setting?");
$this->server->getAsyncPool()->submitTask(new ChunkRequestTask($this, $x, $z, $chunk));
$this->server->getAsyncPool()->submitTask($task = new ChunkRequestTask($this, $x, $z, $chunk));
$this->chunkSendTasks[$index] = $task;
$this->timings->syncChunkSendPrepareTimer->stopTiming();
}
@ -2503,24 +2509,14 @@ class Level implements ChunkManager, Metadatable{
$this->timings->syncChunkSendTimer->startTiming();
$index = Level::chunkHash($x, $z);
unset($this->chunkSendTasks[$index]);
if(!isset($this->chunkCache[$index]) and $this->server->getMemoryManager()->canUseChunkCache()){
$this->chunkCache[$index] = $payload;
$this->sendChunkFromCache($x, $z);
$this->timings->syncChunkSendTimer->stopTiming();
return;
$this->chunkCache[$index] = $payload;
$this->sendChunkFromCache($x, $z);
if(!$this->server->getMemoryManager()->canUseChunkCache()){
unset($this->chunkCache[$index]);
}
if(isset($this->chunkSendTasks[$index])){
foreach($this->chunkSendQueue[$index] as $player){
/** @var Player $player */
if($player->isConnected() and isset($player->usedChunks[$index])){
$player->sendChunk($x, $z, $payload);
}
}
unset($this->chunkSendQueue[$index]);
unset($this->chunkSendTasks[$index]);
}
$this->timings->syncChunkSendTimer->stopTiming();
}
@ -2754,6 +2750,8 @@ class Level implements ChunkManager, Metadatable{
unset($this->chunkCache[$chunkHash]);
unset($this->blockCache[$chunkHash]);
unset($this->changedBlocks[$chunkHash]);
unset($this->chunkSendQueue[$chunkHash]);
unset($this->chunkSendTasks[$chunkHash]);
$this->timings->doChunkUnload->stopTiming();

View File

@ -295,7 +295,7 @@ class AsyncPool{
}
$this->removeTask($task);
}elseif($task->isTerminated() or $task->isCrashed()){
}elseif($task->isCrashed()){
$this->logger->critical("Could not execute asynchronous task " . (new \ReflectionClass($task))->getShortName() . ": Task crashed");
$this->removeTask($task, true);
}

View File

@ -80,7 +80,7 @@ abstract class AsyncTask extends Collectable{
}
public function isCrashed() : bool{
return $this->crashed;
return $this->crashed or $this->isTerminated();
}
/**

View File

@ -204,10 +204,16 @@ class MainLogger extends \AttachableThreadedLogger{
$errno = $errorConversion[$errno] ?? $errno;
$errstr = preg_replace('/\s+/', ' ', trim($errstr));
$errfile = Utils::cleanPath($errfile);
$this->log($type, get_class($e) . ": \"$errstr\" ($errno) in \"$errfile\" at line $errline");
foreach(Utils::getTrace(0, $trace) as $i => $line){
$this->debug($line, true);
}
$message = get_class($e) . ": \"$errstr\" ($errno) in \"$errfile\" at line $errline";
$stack = Utils::getTrace(0, $trace);
$this->synchronized(function() use ($type, $message, $stack) : void{
$this->log($type, $message);
foreach($stack as $line){
$this->debug($line, true);
}
});
$this->syncFlushBuffer();
}
@ -259,19 +265,22 @@ class MainLogger extends \AttachableThreadedLogger{
}
$message = sprintf($this->format, date("H:i:s", $now), $color, $threadName, $prefix, $message);
$cleanMessage = TextFormat::clean($message);
if($this->mainThreadHasFormattingCodes and Terminal::hasFormattingCodes()){ //hasFormattingCodes() lazy-inits colour codes because we don't know if they've been registered on this thread
echo Terminal::toANSI($message) . PHP_EOL;
}else{
echo $cleanMessage . PHP_EOL;
}
$this->synchronized(function() use ($message, $level, $now) : void{
$cleanMessage = TextFormat::clean($message);
foreach($this->attachments as $attachment){
$attachment->call($level, $message);
}
if($this->mainThreadHasFormattingCodes and Terminal::hasFormattingCodes()){ //hasFormattingCodes() lazy-inits colour codes because we don't know if they've been registered on this thread
echo Terminal::toANSI($message) . PHP_EOL;
}else{
echo $cleanMessage . PHP_EOL;
}
$this->logStream[] = date("Y-m-d", $now) . " " . $cleanMessage . PHP_EOL;
foreach($this->attachments as $attachment){
$attachment->call($level, $message);
}
$this->logStream[] = date("Y-m-d", $now) . " " . $cleanMessage . PHP_EOL;
});
}
public function syncFlushBuffer(){