Issue information

Issue ID
#4737
Status
Fixed
Severity
Medium
Started
Hercules Elf Bot
Jan 31, 2011 14:00
Last Post
Hercules Elf Bot
Jan 31, 2011 14:00
Confirmation
N/A

Hercules Elf Bot - Jan 31, 2011 14:00

Originally posted by [b]Ai4rei[/b]
http://www.eathena.ws/board/index.php?autocom=bugtracker&showbug=4737

Observed while doing some stress testing on eAthena, also previously reported in Map-server Crash.

While having around 2000 online sessions, the host machine became low on memory and started to swap out and freezing up the char-server for a while. During that, the sessions that were online on map-server timed out and the map-server closed, while it attempted to save the characters, due to a rejected allocation of 256MB in realloc_writefifo.

Two issues with the WFIFO reallocation contribute to this problem. The major one of them is, that WFIFOSET calls realloc_writefifo with "current WFIFO data length"+"reserve", although realloc_writefifo is supposed to receive 'addition', which means, only the "reserve" itself. So as long the write buffer cannot be sent/flushed (since the other server is not reading data), every call to WFIFOSET causes the WFIFO size to grow to twice it's current length plus the reserve, which is 64k by default for server connections:
CODE
    // always keep a WFIFO_SIZE reserve in the buffer
    // For inter-server connections, let the reserve be 1/4th of the link size.
    newreserve = s->wdata_size + ( s->flag.server ? FIFOSIZE_SERVERLINK / 4 : WFIFO_SIZE);

    // readjust the buffer to the newly chosen size
    realloc_writefifo(fd, newreserve);

The WFIFOHEAD macro, which also uses realloc_writefifo, does this properly.

The second issue only rounds up the first failure, so that the allocations take place in whole mega bytes, because the 'newsize' in realloc_writefifo is being increased by adding itself, rather than WFIFO_SIZE as specified by the grow rule in the comment:
CODE
    if( session[fd]->wdata_size + addition  > session[fd]->max_wdata )
    {    // grow rule; grow in multiples of WFIFO_SIZE
        newsize = WFIFO_SIZE;
        while( session[fd]->wdata_size + addition > newsize ) newsize += newsize;
    }


Currently the map-server WFIFO is about 1-16MB with 2000 players (moderate processing lag). With this issue fixed the WFIFO is kept around few kilobytes up to 3MB, though the WFIFO is reallocated more often when growing (16k steps), which can be changed by altering the WFIFO_SIZE define. Related r11503, r11571, r11886 and r12232.

This post has been edited by Ai4rei: Jan 31 2011, 06:38 AM