Skip to content

Commit

Permalink
Add areastore cache
Browse files Browse the repository at this point in the history
  • Loading branch information
est31 committed Jul 9, 2015
1 parent 819fda7 commit 6b85607
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 15 deletions.
64 changes: 62 additions & 2 deletions src/areastore.cpp
Expand Up @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#include "areastore.h"
#include "util/serialize.h"
#include "util/container.h"
#include "log.h" // TODO remove (for debugging)

#if USE_SPATIAL
Expand Down Expand Up @@ -133,6 +134,65 @@ void AreaStore::serialize(std::ostream &os) const
forEach(&serialize_area, &os);
}


void AreaStore::invalidateCache()
{
if (cache_enabled) {
m_res_cache.invalidate();
}
}


void AreaStore::setCacheEnabled(bool enabled)
{
if (!enabled && cache_enabled) {
invalidateCache();
}
}

inline static void other_val(s16 p, u8 r)
{
return p >= 0 ? (p + r - 1) : (p - r + 1);
}

void AreaStore::cacheMiss(void *data, const v3s16 &mpos, std::vector<Area *> *dest)
{
AreaStore *as = (AreaStore *)data;
u8 r = as->m_cacheblock_radius;

// get the point at the other side of the mapblock
v3s16 mpos_other;
mpos_other.X = other_val(mpos.X, r);
mpos_other.Y = other_val(mpos.Y, r);
mpos_other.Z = other_val(mpos.Z, r);

// extremify both points
v3s16 minedge;
v3s16 maxedge;
AST_EXTREMIFY(minedge, maxedge, mpos, mpos_other)

as->getAreasInArea(dest, minedge, maxedge, true);
}

void AreaStore::getAreasForPos(std::vector<Area *> *result, v3s16 pos)
{
if (cache_enabled) {
v3s16 mblock = getContainerPos(pos, m_cacheblock_radius);
std::vector<Area *> &pre_list = m_res_cache.lookupCache(mblock);

size_t s_p_l = pre_list.size();
for (size_t i = 0; i < s_p_l; i++) {
Area *b = pre_list[i];
if (AST_CONTAINS_PT(b, pos)) {
result->push_back(b);
}
}
} else {
return getAreasForPosImpl(result, pos);
}
}


void VectorAreaStore::insertArea(const Area &a)
{
areas_map[a.id] = a;
Expand Down Expand Up @@ -165,7 +225,7 @@ bool VectorAreaStore::removeArea(u32 id)
return false;
}

void VectorAreaStore::getAreasForPos(std::vector<Area *> *result, v3s16 pos)
void VectorAreaStore::getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos)
{
size_t msiz = m_areas.size();
for (size_t i = 0; i < msiz; i++) {
Expand Down Expand Up @@ -239,7 +299,7 @@ bool SpatialAreaStore::removeArea(u32 id)
}
}

void SpatialAreaStore::getAreasForPos(std::vector<Area *> *result, v3s16 pos)
void SpatialAreaStore::getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos)
{
VectorResultVisitor visitor(result, this);
m_tree->pointLocationQuery(get_spatial_point(pos), visitor);
Expand Down
45 changes: 32 additions & 13 deletions src/areastore.h
Expand Up @@ -30,13 +30,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef ANDROID
#include "cmake_config.h"
#endif

#if USE_SPATIAL

#include <SpatialIndex.h>
#include "util/serialize.h"
#include <SpatialIndex.h>
#include "util/serialize.h"
#endif

#define AST_EXTREMIFY(min, max, pa, pb) \
min.X = MYMIN(pa.X, pb.X); \
min.Y = MYMIN(pa.Y, pb.Y); \
min.Z = MYMIN(pa.Z, pb.Z);

typedef struct Area {
Area()
{
Expand All @@ -54,12 +57,7 @@ typedef struct Area {
v3s16 nminedge;
v3s16 nmaxedge;

nminedge.X = MYMIN(minedge.X, maxedge.X);
nminedge.Y = MYMIN(minedge.Y, maxedge.Y);
nminedge.Z = MYMIN(minedge.Z, maxedge.Z);
nmaxedge.X = MYMAX(minedge.X, maxedge.X);
nmaxedge.Y = MYMAX(minedge.Y, maxedge.Y);
nmaxedge.Z = MYMAX(minedge.Z, maxedge.Z);
AST_EXTREMIFY(nminedge, nmaxedge, minedge, maxedge)

maxedge = nmaxedge;
minedge = nminedge;
Expand All @@ -78,11 +76,14 @@ class AreaStore {
std::map<u32, Area> areas_map;
u16 count;
PcgRandom random;
void invalidateCache();
virtual void getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos) = 0;
bool cache_enabled; // don't write to this from subclasses, only read.
public:
virtual void insertArea(const Area &a) = 0;
virtual void reserve(size_t count) {};
virtual bool removeArea(u32 id) = 0;
virtual void getAreasForPos(std::vector<Area *> *result, v3s16 pos) = 0;
void getAreasForPos(std::vector<Area *> *result, v3s16 pos);
virtual void getAreasInArea(std::vector<Area *> *result,
v3s16 minedge, v3s16 maxedge, bool accept_overlap) = 0;

Expand All @@ -94,20 +95,37 @@ class AreaStore {
virtual ~AreaStore()
{}

AreaStore() :
m_res_cache(1000, &cacheMiss, this),
cache_enabled(false),
m_cacheblock_radius(64),
{
cache_enabled = false;
m_cacheblock_radius = 64;
}

void setCacheEnabled(bool enabled);

u32 getFreeId(v3s16 minedge, v3s16 maxedge);
const Area *getArea(u32 id) const;
u16 size() const;
bool deserialize(std::istream &is);
void serialize(std::ostream &is) const;
private:
static void cacheMiss(void *data, const K &val, V *dest);
u8 m_cacheblock_radius; // if you modify this, call invalidateCache()
LRUCache<v3s16, std::vector<Area *>> m_res_cache;

};


class VectorAreaStore : public AreaStore {
protected:
virtual void getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos);
public:
virtual void insertArea(const Area &a);
virtual void reserve(size_t count);
virtual bool removeArea(u32 id);
virtual void getAreasForPos(std::vector<Area *> *result, v3s16 pos);
virtual void getAreasInArea(std::vector<Area *> *result,
v3s16 minedge, v3s16 maxedge, bool accept_overlap);
virtual bool forEach(bool (*callback)(void *args, Area *a), void *args) const;
Expand All @@ -120,11 +138,12 @@ class VectorAreaStore : public AreaStore {
//#define SPATIAL_DLEN sizeof(u32)

class SpatialAreaStore : public AreaStore {
protected:
virtual void getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos);
public:
SpatialAreaStore();
virtual void insertArea(const Area &a);
virtual bool removeArea(u32 id);
virtual void getAreasForPos(std::vector<Area *> *result, v3s16 pos);
virtual void getAreasInArea(std::vector<Area *> *result,
v3s16 minedge, v3s16 maxedge, bool accept_overlap);
virtual bool forEach(bool (*callback)(void *args, Area *a), void *args) const;
Expand Down
61 changes: 61 additions & 0 deletions src/util/container.h
Expand Up @@ -309,5 +309,66 @@ class MutexedQueue
JSemaphore m_size;
};

template<typename K, typename V>
class LRUCache
{
public:
LRUCache(size_t limit, void (*cache_miss)(void *data, const K &key, V *dest),
void *data)
{
m_limit = limit;
m_cache_miss = cache_miss;
m_cache_miss_data = data;
}

void invalidate()
{
m_map.clear();
m_queue.clear();
}

const *V lookupCache(const K &key)
{
cache_type::iterator it = m_map.find(key);
V &ret;
if (it != m_map.end()) {
// found!

std::pair<std::list<K>::iterator, V> &entry = it->second;

ret = entry.second;

// update the usage information
m_queue.erase(entry.first);
m_queue.push_front(key);

} else {
// cache miss -- enter into cache
std::pair<std::list<K>::iterator, V> &entry =
m_map[key];
ret = entry.second;
m_cache_miss(m_cache_miss_data, key, &entry.second);

// delete old entries
if (m_queue.size() == m_limit) {
const K &id = m_queue.back();
m_map.erase(id);
m_queue.pop_back();
}

entry.first = m_queue.begin();
m_queue.push_front(key);
}
return ret;
}
private:
void (*m_cache_miss)(void *data, const K &key, V *dest);
void *m_cache_miss_data;
size_t m_limit;
typedef std::map<K, std::pair<std::list<K>::iterator, V> > cache_type;
cache_type m_map;
std::list<K> m_queue;
};

#endif

0 comments on commit 6b85607

Please sign in to comment.