#include "database-dummy.h"
#include "database-sqlite3.h"
#include <deque>
+#include <queue>
#if USE_LEVELDB
#include "database-leveldb.h"
#endif
return false;
}
+struct TimeOrderedMapBlock {
+ MapSector *sect;
+ MapBlock *block;
+
+ TimeOrderedMapBlock(MapSector *sect, MapBlock *block) :
+ sect(sect),
+ block(block)
+ {}
+
+ bool operator<(const TimeOrderedMapBlock &b) const
+ {
+ return block->getUsageTimer() < b.block->getUsageTimer();
+ };
+};
+
/*
Updates usage timers
*/
-void Map::timerUpdate(float dtime, float unload_timeout,
+void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks,
std::vector<v3s16> *unloaded_blocks)
{
bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
u32 block_count_all = 0;
beginSave();
- for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
- si != m_sectors.end(); ++si) {
- MapSector *sector = si->second;
- bool all_blocks_deleted = true;
+ // If there is no practical limit, we spare creation of mapblock_queue
+ if (max_loaded_blocks == (u32)-1) {
+ for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
+ si != m_sectors.end(); ++si) {
+ MapSector *sector = si->second;
- MapBlockVect blocks;
- sector->getBlocks(blocks);
+ bool all_blocks_deleted = true;
- for(MapBlockVect::iterator i = blocks.begin();
- i != blocks.end(); ++i) {
- MapBlock *block = (*i);
+ MapBlockVect blocks;
+ sector->getBlocks(blocks);
- block->incrementUsageTimer(dtime);
+ for (MapBlockVect::iterator i = blocks.begin();
+ i != blocks.end(); ++i) {
+ MapBlock *block = (*i);
- if(block->refGet() == 0 && block->getUsageTimer() > unload_timeout) {
- v3s16 p = block->getPos();
+ block->incrementUsageTimer(dtime);
- // Save if modified
- if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) {
- modprofiler.add(block->getModifiedReason(), 1);
- if (!saveBlock(block))
- continue;
- saved_blocks_count++;
- }
+ if (block->refGet() == 0
+ && block->getUsageTimer() > unload_timeout) {
+ v3s16 p = block->getPos();
+
+ // Save if modified
+ if (block->getModified() != MOD_STATE_CLEAN
+ && save_before_unloading) {
+ modprofiler.add(block->getModifiedReasonString(), 1);
+ if (!saveBlock(block))
+ continue;
+ saved_blocks_count++;
+ }
- // Delete from memory
- sector->deleteBlock(block);
+ // Delete from memory
+ sector->deleteBlock(block);
- if(unloaded_blocks)
- unloaded_blocks->push_back(p);
+ if (unloaded_blocks)
+ unloaded_blocks->push_back(p);
- deleted_blocks_count++;
+ deleted_blocks_count++;
+ } else {
+ all_blocks_deleted = false;
+ block_count_all++;
+ }
}
- else {
- all_blocks_deleted = false;
- block_count_all++;
+
+ if (all_blocks_deleted) {
+ sector_deletion_queue.push_back(si->first);
}
}
+ } else {
+ std::priority_queue<TimeOrderedMapBlock> mapblock_queue;
+ for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
+ si != m_sectors.end(); ++si) {
+ MapSector *sector = si->second;
+
+ MapBlockVect blocks;
+ sector->getBlocks(blocks);
+
+ for(MapBlockVect::iterator i = blocks.begin();
+ i != blocks.end(); ++i) {
+ MapBlock *block = (*i);
- if(all_blocks_deleted) {
- sector_deletion_queue.push_back(si->first);
+ block->incrementUsageTimer(dtime);
+ mapblock_queue.push(TimeOrderedMapBlock(sector, block));
+ }
+ }
+ block_count_all = mapblock_queue.size();
+ // Delete old blocks, and blocks over the limit from the memory
+ while (!mapblock_queue.empty() && (mapblock_queue.size() > max_loaded_blocks
+ || mapblock_queue.top().block->getUsageTimer() > unload_timeout)) {
+ TimeOrderedMapBlock b = mapblock_queue.top();
+ mapblock_queue.pop();
+
+ MapBlock *block = b.block;
+
+ if (block->refGet() != 0)
+ continue;
+
+ v3s16 p = block->getPos();
+
+ // Save if modified
+ if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) {
+ modprofiler.add(block->getModifiedReasonString(), 1);
+ if (!saveBlock(block))
+ continue;
+ saved_blocks_count++;
+ }
+
+ // Delete from memory
+ b.sect->deleteBlock(block);
+
+ if (unloaded_blocks)
+ unloaded_blocks->push_back(p);
+
+ deleted_blocks_count++;
+ block_count_all--;
+ }
+ // Delete empty sectors
+ for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
+ si != m_sectors.end(); ++si) {
+ if (si->second->empty()) {
+ sector_deletion_queue.push_back(si->first);
+ }
}
}
endSave();
void Map::unloadUnreferencedBlocks(std::vector<v3s16> *unloaded_blocks)
{
- timerUpdate(0.0, -1.0, unloaded_blocks);
+ timerUpdate(0.0, -1.0, 0, unloaded_blocks);
}
void Map::deleteSectors(std::vector<v2s16> §orList)
v3s16 bpmin = getNodeBlockPos(p1);
v3s16 bpmax = getNodeBlockPos(p2);
+ VoxelArea area(p1, p2);
+
for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
for (s16 x = bpmin.X; x <= bpmax.X; x++) {
v3s16 p_base = blockpos * MAP_BLOCKSIZE;
std::vector<v3s16> keys = block->m_node_metadata.getAllKeys();
- for (size_t i = 0; i != keys.size(); i++)
- positions_with_meta.push_back(keys[i] + p_base);
+ for (size_t i = 0; i != keys.size(); i++) {
+ v3s16 p(keys[i] + p_base);
+ if (!area.contains(p))
+ continue;
+
+ positions_with_meta.push_back(p);
+ }
}
return positions_with_meta;
Set block as modified
*/
block->raiseModified(MOD_STATE_WRITE_NEEDED,
- "finishBlockMake expireDayNightDiff");
+ MOD_REASON_EXPIRE_DAYNIGHTDIFF);
}
/*
/*
Do not create over-limit
*/
- if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
- || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
- || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
- || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
+ const static u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
+ g_settings->getU16("map_generation_limit"));
+ if(p2d.X < -map_gen_limit / MAP_BLOCKSIZE
+ || p2d.X > map_gen_limit / MAP_BLOCKSIZE
+ || p2d.Y < -map_gen_limit / MAP_BLOCKSIZE
+ || p2d.Y > map_gen_limit / MAP_BLOCKSIZE)
throw InvalidPositionException("createSector(): pos. over limit");
/*
/*
Do not create over-limit
*/
- if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
- || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
- || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
- || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
- || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
- || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
+ if (blockpos_over_limit(p))
throw InvalidPositionException("createBlock(): pos. over limit");
v2s16 p2d(p.X, p.Z);
save_started = true;
}
- modprofiler.add(block->getModifiedReason(), 1);
+ modprofiler.add(block->getModifiedReasonString(), 1);
saveBlock(block);
block_count++;