Skip to content

Commit a8e238e

Browse files
committedAug 13, 2015
Add count based unload limit for mapblocks
1 parent 2b04ab8 commit a8e238e

File tree

8 files changed

+152
-63
lines changed

8 files changed

+152
-63
lines changed
 

Diff for: ‎minetest.conf.example

+3
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@
9494
#random_input = false
9595
# Timeout for client to remove unused map data from memory
9696
#client_unload_unused_data_timeout = 600
97+
# Maximum number of mapblocks for client to be kept in memory
98+
# Set to -1 for unlimited amount
99+
#client_mapblock_limit = 1000
97100
# Whether to fog out the end of the visible area
98101
#enable_fog = true
99102
# Whether to show the client debug info (has the same effect as hitting F5)

Diff for: ‎src/client.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,9 @@ void Client::step(float dtime)
421421
ScopeProfiler sp(g_profiler, "Client: map timer and unload");
422422
std::vector<v3s16> deleted_blocks;
423423
m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
424-
g_settings->getFloat("client_unload_unused_data_timeout"),
425-
&deleted_blocks);
424+
g_settings->getFloat("client_unload_unused_data_timeout"),
425+
g_settings->getS32("client_mapblock_limit"),
426+
&deleted_blocks);
426427

427428
/*
428429
Send info to server

Diff for: ‎src/defaultsettings.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ void set_default_settings(Settings *settings)
104104
settings->setDefault("address", "");
105105
settings->setDefault("random_input", "false");
106106
settings->setDefault("client_unload_unused_data_timeout", "600");
107+
settings->setDefault("client_mapblock_limit", "1000");
107108
settings->setDefault("enable_fog", "true");
108109
settings->setDefault("fov", "72");
109110
settings->setDefault("view_bobbing", "true");

Diff for: ‎src/map.cpp

+107-31
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
4343
#include "database-dummy.h"
4444
#include "database-sqlite3.h"
4545
#include <deque>
46+
#include <queue>
4647
#if USE_LEVELDB
4748
#include "database-leveldb.h"
4849
#endif
@@ -1399,10 +1400,25 @@ bool Map::getDayNightDiff(v3s16 blockpos)
13991400
return false;
14001401
}
14011402

1403+
struct TimeOrderedMapBlock {
1404+
MapSector *sect;
1405+
MapBlock *block;
1406+
1407+
TimeOrderedMapBlock(MapSector *sect, MapBlock *block) :
1408+
sect(sect),
1409+
block(block)
1410+
{}
1411+
1412+
bool operator<(const TimeOrderedMapBlock &b) const
1413+
{
1414+
return block->getUsageTimer() < b.block->getUsageTimer();
1415+
};
1416+
};
1417+
14021418
/*
14031419
Updates usage timers
14041420
*/
1405-
void Map::timerUpdate(float dtime, float unload_timeout,
1421+
void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks,
14061422
std::vector<v3s16> *unloaded_blocks)
14071423
{
14081424
bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
@@ -1416,48 +1432,108 @@ void Map::timerUpdate(float dtime, float unload_timeout,
14161432
u32 block_count_all = 0;
14171433

14181434
beginSave();
1419-
for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
1420-
si != m_sectors.end(); ++si) {
1421-
MapSector *sector = si->second;
14221435

1423-
bool all_blocks_deleted = true;
1436+
// If there is no practical limit, we spare creation of mapblock_queue
1437+
if (max_loaded_blocks == (u32)-1) {
1438+
for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
1439+
si != m_sectors.end(); ++si) {
1440+
MapSector *sector = si->second;
14241441

1425-
MapBlockVect blocks;
1426-
sector->getBlocks(blocks);
1442+
bool all_blocks_deleted = true;
14271443

1428-
for(MapBlockVect::iterator i = blocks.begin();
1429-
i != blocks.end(); ++i) {
1430-
MapBlock *block = (*i);
1444+
MapBlockVect blocks;
1445+
sector->getBlocks(blocks);
14311446

1432-
block->incrementUsageTimer(dtime);
1447+
for (MapBlockVect::iterator i = blocks.begin();
1448+
i != blocks.end(); ++i) {
1449+
MapBlock *block = (*i);
14331450

1434-
if(block->refGet() == 0 && block->getUsageTimer() > unload_timeout) {
1435-
v3s16 p = block->getPos();
1451+
block->incrementUsageTimer(dtime);
14361452

1437-
// Save if modified
1438-
if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) {
1439-
modprofiler.add(block->getModifiedReasonString(), 1);
1440-
if (!saveBlock(block))
1441-
continue;
1442-
saved_blocks_count++;
1443-
}
1453+
if (block->refGet() == 0
1454+
&& block->getUsageTimer() > unload_timeout) {
1455+
v3s16 p = block->getPos();
14441456

1445-
// Delete from memory
1446-
sector->deleteBlock(block);
1457+
// Save if modified
1458+
if (block->getModified() != MOD_STATE_CLEAN
1459+
&& save_before_unloading) {
1460+
modprofiler.add(block->getModifiedReasonString(), 1);
1461+
if (!saveBlock(block))
1462+
continue;
1463+
saved_blocks_count++;
1464+
}
14471465

1448-
if(unloaded_blocks)
1449-
unloaded_blocks->push_back(p);
1466+
// Delete from memory
1467+
sector->deleteBlock(block);
1468+
1469+
if (unloaded_blocks)
1470+
unloaded_blocks->push_back(p);
1471+
1472+
deleted_blocks_count++;
1473+
} else {
1474+
all_blocks_deleted = false;
1475+
block_count_all++;
1476+
}
1477+
}
14501478

1451-
deleted_blocks_count++;
1479+
if (all_blocks_deleted) {
1480+
sector_deletion_queue.push_back(si->first);
14521481
}
1453-
else {
1454-
all_blocks_deleted = false;
1455-
block_count_all++;
1482+
}
1483+
} else {
1484+
std::priority_queue<TimeOrderedMapBlock> mapblock_queue;
1485+
for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
1486+
si != m_sectors.end(); ++si) {
1487+
MapSector *sector = si->second;
1488+
1489+
MapBlockVect blocks;
1490+
sector->getBlocks(blocks);
1491+
1492+
for(MapBlockVect::iterator i = blocks.begin();
1493+
i != blocks.end(); ++i) {
1494+
MapBlock *block = (*i);
1495+
1496+
block->incrementUsageTimer(dtime);
1497+
mapblock_queue.push(TimeOrderedMapBlock(sector, block));
14561498
}
14571499
}
1500+
block_count_all = mapblock_queue.size();
1501+
// Delete old blocks, and blocks over the limit from the memory
1502+
while (mapblock_queue.size() > max_loaded_blocks
1503+
|| mapblock_queue.top().block->getUsageTimer() > unload_timeout) {
1504+
TimeOrderedMapBlock b = mapblock_queue.top();
1505+
mapblock_queue.pop();
1506+
1507+
MapBlock *block = b.block;
1508+
1509+
if (block->refGet() != 0)
1510+
continue;
1511+
1512+
v3s16 p = block->getPos();
1513+
1514+
// Save if modified
1515+
if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) {
1516+
modprofiler.add(block->getModifiedReasonString(), 1);
1517+
if (!saveBlock(block))
1518+
continue;
1519+
saved_blocks_count++;
1520+
}
14581521

1459-
if(all_blocks_deleted) {
1460-
sector_deletion_queue.push_back(si->first);
1522+
// Delete from memory
1523+
b.sect->deleteBlock(block);
1524+
1525+
if (unloaded_blocks)
1526+
unloaded_blocks->push_back(p);
1527+
1528+
deleted_blocks_count++;
1529+
block_count_all--;
1530+
}
1531+
// Delete empty sectors
1532+
for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
1533+
si != m_sectors.end(); ++si) {
1534+
if (si->second->empty()) {
1535+
sector_deletion_queue.push_back(si->first);
1536+
}
14611537
}
14621538
}
14631539
endSave();
@@ -1484,7 +1560,7 @@ void Map::timerUpdate(float dtime, float unload_timeout,
14841560

14851561
void Map::unloadUnreferencedBlocks(std::vector<v3s16> *unloaded_blocks)
14861562
{
1487-
timerUpdate(0.0, -1.0, unloaded_blocks);
1563+
timerUpdate(0.0, -1.0, 0, unloaded_blocks);
14881564
}
14891565

14901566
void Map::deleteSectors(std::vector<v2s16> &sectorList)

Diff for: ‎src/map.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ class Map /*: public NodeContainer*/
277277
Updates usage timers and unloads unused blocks and sectors.
278278
Saves modified blocks before unloading on MAPTYPE_SERVER.
279279
*/
280-
void timerUpdate(float dtime, float unload_timeout,
280+
void timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks,
281281
std::vector<v3s16> *unloaded_blocks=NULL);
282282

283283
/*

Diff for: ‎src/mapsector.cpp

+20-15
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ MapBlock * MapSector::getBlockBuffered(s16 y)
5959
if(m_block_cache != NULL && y == m_block_cache_y){
6060
return m_block_cache;
6161
}
62-
62+
6363
// If block doesn't exist, return NULL
6464
std::map<s16, MapBlock*>::iterator n = m_blocks.find(y);
6565
if(n == m_blocks.end())
@@ -70,11 +70,11 @@ MapBlock * MapSector::getBlockBuffered(s16 y)
7070
else{
7171
block = n->second;
7272
}
73-
73+
7474
// Cache the last result
7575
m_block_cache_y = y;
7676
m_block_cache = block;
77-
77+
7878
return block;
7979
}
8080

@@ -88,16 +88,16 @@ MapBlock * MapSector::createBlankBlockNoInsert(s16 y)
8888
assert(getBlockBuffered(y) == NULL); // Pre-condition
8989

9090
v3s16 blockpos_map(m_pos.X, y, m_pos.Y);
91-
91+
9292
MapBlock *block = new MapBlock(m_parent, blockpos_map, m_gamedef);
93-
93+
9494
return block;
9595
}
9696

9797
MapBlock * MapSector::createBlankBlock(s16 y)
9898
{
9999
MapBlock *block = createBlankBlockNoInsert(y);
100-
100+
101101
m_blocks[y] = block;
102102

103103
return block;
@@ -114,7 +114,7 @@ void MapSector::insertBlock(MapBlock *block)
114114

115115
v2s16 p2d(block->getPos().X, block->getPos().Z);
116116
assert(p2d == m_pos);
117-
117+
118118
// Insert into container
119119
m_blocks[block_y] = block;
120120
}
@@ -125,7 +125,7 @@ void MapSector::deleteBlock(MapBlock *block)
125125

126126
// Clear from cache
127127
m_block_cache = NULL;
128-
128+
129129
// Remove from container
130130
m_blocks.erase(block_y);
131131

@@ -142,6 +142,11 @@ void MapSector::getBlocks(MapBlockVect &dest)
142142
}
143143
}
144144

145+
bool MapSector::empty()
146+
{
147+
return m_blocks.empty();
148+
}
149+
145150
/*
146151
ServerMapSector
147152
*/
@@ -159,18 +164,18 @@ void ServerMapSector::serialize(std::ostream &os, u8 version)
159164
{
160165
if(!ser_ver_supported(version))
161166
throw VersionMismatchException("ERROR: MapSector format not supported");
162-
167+
163168
/*
164169
[0] u8 serialization version
165170
+ heightmap data
166171
*/
167-
172+
168173
// Server has both of these, no need to support not having them.
169174
//assert(m_objects != NULL);
170175

171176
// Write version
172177
os.write((char*)&version, 1);
173-
178+
174179
/*
175180
Add stuff here, if needed
176181
*/
@@ -193,18 +198,18 @@ ServerMapSector* ServerMapSector::deSerialize(
193198
/*
194199
Read stuff
195200
*/
196-
201+
197202
// Read version
198203
u8 version = SER_FMT_VER_INVALID;
199204
is.read((char*)&version, 1);
200-
205+
201206
if(!ser_ver_supported(version))
202207
throw VersionMismatchException("ERROR: MapSector format not supported");
203-
208+
204209
/*
205210
Add necessary reading stuff here
206211
*/
207-
212+
208213
/*
209214
Get or create sector
210215
*/

0 commit comments

Comments
 (0)
Please sign in to comment.