synchronized regfiles
This commit is contained in:
parent
7c4c511826
commit
b6900f5d4e
@ -144,29 +144,13 @@ ubyte* WorldFiles::decompress(const ubyte* src, size_t srclen, size_t dstlen) {
|
||||
return decompressed;
|
||||
}
|
||||
|
||||
int WorldFiles::getVoxelRegionVersion(int x, int z) {
|
||||
regfile* rf = getRegFile(glm::ivec3(x, z, REGION_LAYER_VOXELS), getRegionsFolder());
|
||||
if (rf == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return rf->version;
|
||||
}
|
||||
|
||||
int WorldFiles::getVoxelRegionsVersion() {
|
||||
fs::path regionsFolder = getRegionsFolder();
|
||||
if (!fs::is_directory(regionsFolder)) {
|
||||
return REGION_FORMAT_VERSION;
|
||||
}
|
||||
for (auto file : fs::directory_iterator(regionsFolder)) {
|
||||
int x;
|
||||
int z;
|
||||
if (!parseRegionFilename(file.path().stem().string(), x, z)) {
|
||||
continue;
|
||||
}
|
||||
regfile* rf = getRegFile(glm::ivec3(x, z, REGION_LAYER_VOXELS), regionsFolder);
|
||||
return rf->version;
|
||||
}
|
||||
return REGION_FORMAT_VERSION;
|
||||
inline void calc_reg_coords(
|
||||
int x, int z, int& regionX, int& regionZ, int& localX, int& localZ
|
||||
) {
|
||||
regionX = floordiv(x, REGION_SIZE);
|
||||
regionZ = floordiv(z, REGION_SIZE);
|
||||
localX = x - (regionX * REGION_SIZE);
|
||||
localZ = z - (regionZ * REGION_SIZE);
|
||||
}
|
||||
|
||||
|
||||
@ -174,10 +158,8 @@ int WorldFiles::getVoxelRegionsVersion() {
|
||||
/// @param x chunk.x
|
||||
/// @param z chunk.z
|
||||
void WorldFiles::put(int x, int z, const ubyte* voxelData) {
|
||||
int regionX = floordiv(x, REGION_SIZE);
|
||||
int regionZ = floordiv(z, REGION_SIZE);
|
||||
int localX = x - (regionX * REGION_SIZE);
|
||||
int localZ = z - (regionZ * REGION_SIZE);
|
||||
int regionX, regionZ, localX, localZ;
|
||||
calc_reg_coords(x, z, regionX, regionZ, localX, localZ);
|
||||
|
||||
/* Writing Voxels */ {
|
||||
WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ);
|
||||
@ -192,10 +174,8 @@ void WorldFiles::put(int x, int z, const ubyte* voxelData) {
|
||||
void WorldFiles::put(Chunk* chunk){
|
||||
assert(chunk != nullptr);
|
||||
|
||||
int regionX = floordiv(chunk->x, REGION_SIZE);
|
||||
int regionZ = floordiv(chunk->z, REGION_SIZE);
|
||||
int localX = chunk->x - (regionX * REGION_SIZE);
|
||||
int localZ = chunk->z - (regionZ * REGION_SIZE);
|
||||
int regionX, regionZ, localX, localZ;
|
||||
calc_reg_coords(chunk->x, chunk->z, regionX, regionZ, localX, localZ);
|
||||
|
||||
/* Writing voxels */ {
|
||||
size_t compressedSize;
|
||||
@ -325,13 +305,14 @@ chunk_inventories_map WorldFiles::fetchInventories(int x, int z) {
|
||||
return inventories;
|
||||
}
|
||||
|
||||
ubyte* WorldFiles::getData(regionsmap& regions, const fs::path& folder,
|
||||
int x, int z, int layer, bool compression) {
|
||||
int regionX = floordiv(x, REGION_SIZE);
|
||||
int regionZ = floordiv(z, REGION_SIZE);
|
||||
|
||||
int localX = x - (regionX * REGION_SIZE);
|
||||
int localZ = z - (regionZ * REGION_SIZE);
|
||||
ubyte* WorldFiles::getData(
|
||||
regionsmap& regions,
|
||||
const fs::path& folder,
|
||||
int x, int z, int layer,
|
||||
bool compression
|
||||
) {
|
||||
int regionX, regionZ, localX, localZ;
|
||||
calc_reg_coords(x, z, regionX, regionZ, localX, localZ);
|
||||
|
||||
WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ);
|
||||
ubyte* data = region->getChunkData(localX, localZ);
|
||||
@ -352,41 +333,82 @@ ubyte* WorldFiles::getData(regionsmap& regions, const fs::path& folder,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
regfile* WorldFiles::getRegFile(glm::ivec3 coord, const fs::path& folder) {
|
||||
const auto found = openRegFiles.find(coord);
|
||||
if (found != openRegFiles.end()) {
|
||||
return found->second.get();
|
||||
}
|
||||
if (openRegFiles.size() == MAX_OPEN_REGION_FILES) {
|
||||
// [todo] replace with closing the most unused region
|
||||
auto iter = std::next(openRegFiles.begin(), rand() % openRegFiles.size());
|
||||
openRegFiles.erase(iter);
|
||||
}
|
||||
fs::path filename = folder / getRegionFilename(coord[0], coord[1]);
|
||||
if (!fs::is_regular_file(filename)) {
|
||||
return nullptr;
|
||||
}
|
||||
openRegFiles[coord] = std::make_unique<regfile>(filename);
|
||||
return openRegFiles[coord].get();
|
||||
std::shared_ptr<regfile> WorldFiles::useRegFile(glm::ivec3 coord) {
|
||||
return std::shared_ptr<regfile>(openRegFiles[coord].get(), [this](regfile* ptr) {
|
||||
ptr->inUse = false;
|
||||
regFilesCv.notify_one();
|
||||
});
|
||||
}
|
||||
|
||||
ubyte* WorldFiles::readChunkData(int x,
|
||||
int z,
|
||||
uint32_t& length,
|
||||
fs::path folder,
|
||||
int layer){
|
||||
void WorldFiles::closeRegFile(glm::ivec3 coord) {
|
||||
openRegFiles.erase(coord);
|
||||
regFilesCv.notify_one();
|
||||
}
|
||||
|
||||
// Marks regfile as used and unmarks when shared_ptr dies
|
||||
std::shared_ptr<regfile> WorldFiles::getRegFile(glm::ivec3 coord, const fs::path& folder) {
|
||||
{
|
||||
std::lock_guard lock(regFilesMutex);
|
||||
const auto found = openRegFiles.find(coord);
|
||||
if (found != openRegFiles.end()) {
|
||||
if (found->second->inUse) {
|
||||
throw std::runtime_error("regfile is currently in use");
|
||||
}
|
||||
found->second->inUse = true;
|
||||
return useRegFile(found->first);
|
||||
}
|
||||
}
|
||||
return createRegFile(coord, folder);
|
||||
}
|
||||
|
||||
std::shared_ptr<regfile> WorldFiles::createRegFile(glm::ivec3 coord, const fs::path& folder) {
|
||||
fs::path file = folder / getRegionFilename(coord[0], coord[1]);
|
||||
if (!fs::exists(file)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (openRegFiles.size() == MAX_OPEN_REGION_FILES) {
|
||||
std::unique_lock lock(regFilesMutex);
|
||||
while (true) {
|
||||
bool closed = false;
|
||||
// FIXME: bad choosing algorithm
|
||||
for (auto& entry : openRegFiles) {
|
||||
if (!entry.second->inUse) {
|
||||
closeRegFile(entry.first);
|
||||
closed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (closed) {
|
||||
break;
|
||||
}
|
||||
// notified when any regfile gets out of use or closed
|
||||
regFilesCv.wait(lock);
|
||||
}
|
||||
openRegFiles[coord] = std::make_unique<regfile>(file);
|
||||
return useRegFile(coord);
|
||||
} else {
|
||||
std::lock_guard lock(regFilesMutex);
|
||||
openRegFiles[coord] = std::make_unique<regfile>(file);
|
||||
return useRegFile(coord);
|
||||
}
|
||||
}
|
||||
|
||||
ubyte* WorldFiles::readChunkData(
|
||||
int x,
|
||||
int z,
|
||||
uint32_t& length,
|
||||
fs::path folder,
|
||||
int layer
|
||||
){
|
||||
if (generatorTestMode)
|
||||
return nullptr;
|
||||
|
||||
int regionX = floordiv(x, REGION_SIZE);
|
||||
int regionZ = floordiv(z, REGION_SIZE);
|
||||
int localX = x - (regionX * REGION_SIZE);
|
||||
int localZ = z - (regionZ * REGION_SIZE);
|
||||
int regionX, regionZ, localX, localZ;
|
||||
calc_reg_coords(x, z, regionX, regionZ, localX, localZ);
|
||||
int chunkIndex = localZ * REGION_SIZE + localX;
|
||||
|
||||
glm::ivec3 coord(regionX, regionZ, layer);
|
||||
regfile* rfile = WorldFiles::getRegFile(coord, folder);
|
||||
auto rfile = getRegFile(coord, folder);
|
||||
if (rfile == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -399,7 +421,6 @@ ubyte* WorldFiles::readChunkData(int x,
|
||||
file.seekg(table_offset + chunkIndex * 4);
|
||||
file.read((char*)(&offset), 4);
|
||||
offset = dataio::read_int32_big((const ubyte*)(&offset), 0);
|
||||
|
||||
if (offset == 0){
|
||||
return nullptr;
|
||||
}
|
||||
@ -439,7 +460,10 @@ void WorldFiles::writeRegion(int x, int z, WorldRegion* entry, fs::path folder,
|
||||
glm::ivec3 regcoord(x, z, layer);
|
||||
if (getRegFile(regcoord, folder)) {
|
||||
fetchChunks(entry, x, z, folder, layer);
|
||||
openRegFiles.erase(regcoord);
|
||||
{
|
||||
std::lock_guard lock(regFilesMutex);
|
||||
closeRegFile(regcoord);
|
||||
}
|
||||
}
|
||||
|
||||
char header[REGION_HEADER_SIZE] = REGION_FORMAT_MAGIC;
|
||||
|
||||
@ -8,11 +8,13 @@
|
||||
#include "../voxels/Chunk.h"
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <filesystem>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
@ -66,6 +68,7 @@ public:
|
||||
struct regfile {
|
||||
files::rafile file;
|
||||
int version;
|
||||
bool inUse = false;
|
||||
|
||||
regfile(fs::path filename);
|
||||
};
|
||||
@ -74,6 +77,8 @@ typedef std::unordered_map<glm::ivec2, std::unique_ptr<WorldRegion>> regionsmap;
|
||||
|
||||
class WorldFiles {
|
||||
std::unordered_map<glm::ivec3, std::unique_ptr<regfile>> openRegFiles;
|
||||
std::mutex regFilesMutex;
|
||||
std::condition_variable regFilesCv;
|
||||
|
||||
void writeWorldInfo(const World* world);
|
||||
fs::path getRegionFilename(int x, int y) const;
|
||||
@ -106,7 +111,10 @@ class WorldFiles {
|
||||
|
||||
ubyte* getData(regionsmap& regions, const fs::path& folder, int x, int z, int layer, bool compression);
|
||||
|
||||
regfile* getRegFile(glm::ivec3 coord, const fs::path& folder);
|
||||
std::shared_ptr<regfile> getRegFile(glm::ivec3 coord, const fs::path& folder);
|
||||
void closeRegFile(glm::ivec3 coord);
|
||||
std::shared_ptr<regfile> useRegFile(glm::ivec3 coord);
|
||||
std::shared_ptr<regfile> createRegFile(glm::ivec3 coord, const fs::path& folder);
|
||||
|
||||
fs::path getLightsFolder() const;
|
||||
fs::path getInventoriesFolder() const;
|
||||
@ -131,9 +139,6 @@ public:
|
||||
void put(Chunk* chunk);
|
||||
void put(int x, int z, const ubyte* voxelData);
|
||||
|
||||
int getVoxelRegionVersion(int x, int z);
|
||||
int getVoxelRegionsVersion();
|
||||
|
||||
ubyte* getChunk(int x, int z);
|
||||
light_t* getLights(int x, int z);
|
||||
chunk_inventories_map fetchInventories(int x, int z);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user