Skip to content

Commit

Permalink
add TileCache stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
andreas committed Feb 10, 2024
1 parent 96ae8fc commit 934f03f
Show file tree
Hide file tree
Showing 2 changed files with 263 additions and 0 deletions.
99 changes: 99 additions & 0 deletions provider/include/TileCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/******************************************************************************
*
* Project: AvNav ocharts-provider
* Purpose: Tile Cache
* Author: Andreas Vogel
*
***************************************************************************
* Copyright (C) 2024 by Andreas Vogel *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************
*
*/

#ifndef _TILECACHE_H
#define _TILECACHE_H
#include "Types.h"
#include "ItemStatus.h"
#include "MD5.h"
#include <vector>
#include <atomic>
#include <map>
#include "Timer.h"
#include "SimpleThread.h"
#include "Tiles.h"

class TileCache : public ItemStatus{
public:
using Png=DataPtr;
using Ptr=std::shared_ptr<TileCache>;
class CacheDescription{
public:
int settingsSequence=0;
String setHash;
int setSequence=0;
bool isNewer(const CacheDescription &other) const{
if (settingsSequence == other.settingsSequence &&
setHash == other.setHash
) return false;
if (settingsSequence < other.settingsSequence
|| setSequence < other.setSequence) return false;
return true;
}
bool equals(const CacheDescription &other) const{
return (settingsSequence == other.settingsSequence
&& setHash == other.setHash);
}
};
private:
class CacheEntry{
public:
using Ptr=std::shared_ptr<CacheEntry>;
CacheDescription description;
Png data;
Timer::SteadyTimePoint lastAccess;
size_t size=2*sizeof(MD5Name)+sizeof(Timer::SteadyTimePoint);
CacheEntry(Png d, const CacheDescription &dsc, size_t keySize):
data(d),description(dsc){
lastAccess=Timer::steadyNow();
size+=data->size()+keySize;
size=size/1024;
}
bool isNewer(const CacheEntry &other) const{
return description.isNewer(other.description);
}
};
std::mutex lock;
using Data=std::map<String,CacheEntry::Ptr>;
std::atomic<int> numEntries={0};
std::atomic<int> numKb={0};
size_t maxMem;
Data cache;
String getKey(const TileInfo &tile);
public:
bool stopAudit=false;
TileCache(size_t max);
virtual void ToJson(StatusStream &stream);
void cleanup();
void clean(String setKey="");
void cleanBySettings(int remainingSeqeunce);
bool addTile(Png d, const CacheDescription &description, const TileInfo &tile);
Png getTile(const CacheDescription &description, const TileInfo &tile);
void stop(){stopAudit=true;}

};
#endif
164 changes: 164 additions & 0 deletions provider/src/TileCache.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/******************************************************************************
*
* Project: AvNav ocharts-provider
* Purpose: Tile Cache
* Author: Andreas Vogel
*
***************************************************************************
* Copyright (C) 2024 by Andreas Vogel *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************
*
*/

#include "TileCache.h"
#include "StringHelper.h"
String TileCache::getKey(const TileInfo &tile){
return FMT("%s/%d/%d/%d",tile.chartSetKey,tile.zoom,tile.x,tile.y);
}
void TileCache::ToJson(StatusStream &stream){
stream["numEntries"]=(int)numEntries;
stream["numKb"]=(int)numKb;
}
class CHelper{
public:
String key;
Timer::SteadyTimePoint lastAccess;
size_t kb=0;
CHelper(const String &k, const Timer::SteadyTimePoint &l, size_t s):
key(k),lastAccess(l),kb(s){}
};
void TileCache::cleanup(){
if (numKb <= maxMem) return;
using CHList=std::vector<CHelper>;
std::unique_ptr<CHList> items=std::make_unique<CHList>();
{
Synchronized l(lock);
items->reserve(cache.size());
for (auto &&[key,ci]:cache){
items->push_back(CHelper(key,ci->lastAccess, ci->size));
}
std::sort(items->begin(),items->end(),[](CHelper const & c1, CHelper const & c2){
return c1.lastAccess < c2.lastAccess;
});
auto last=items->begin();
int removeKb=0;
for (auto it=items->begin();it != items->end();it++){
removeKb+=it->kb;
if (removeKb >= (numKb-maxMem)){
last=it;
break;
}
}
for(auto it=items->begin();it!= last && it != items->end();it++){
cache.erase(it->key);
}
int newKb=numKb-removeKb;
if (newKb < 0) newKb=0;
numKb=newKb;
numEntries=cache.size();
}
}
void TileCache::clean(String setKey){
Synchronized l(lock);
size_t current=cache.size();
int currentKb=numKb;
int newKb=0;
if (setKey.empty()){
cache.clear();
numEntries=0;
LOG_INFO("deleted %d entries from tile cache, freeing ~ %dkb",current,(int)numKb);
numKb=0;
return;
}
avnav::erase_if(cache,[setKey,&newKb](Data::reference &item){
bool rt=StringHelper::startsWith(item.first,setKey);
if (!rt){
int kb=item.second->size;
newKb+=kb;
}
return rt;
});
numKb=newKb;
if (cache.size() != current){
LOG_INFO("clean: deleted %d entries from tile cache, freeing ~ %dkb",current,(currentKb-newKb));
}
numEntries=cache.size();
}
void TileCache::cleanBySettings(int remainingSequence){
Synchronized l(lock);
size_t current=cache.size();
int currentKb=numKb;
int newKb=0;
avnav::erase_if(cache,[remainingSequence,&newKb](Data::reference &item){
bool rt=item.second->description.settingsSequence != remainingSequence;
if (!rt){
int kb=item.second->size;
newKb+=kb;
}
return rt;
});
numKb=newKb;
if (cache.size() != current){
LOG_INFO("cleanBySettings: deleted %d entries from tile cache, freeing ~ %dkb",current,(currentKb-newKb));
}
numEntries=cache.size();
}
bool TileCache::addTile(TileCache::Png d, const TileCache::CacheDescription &description, const TileInfo &tile){
Synchronized l(lock);
String key=getKey(tile);
auto cur=cache.find(key);
bool rt=false;
if (cur == cache.end()){
CacheEntry::Ptr ne=std::make_shared<CacheEntry>(d,description,key.size());
cache[key]=ne;
numKb+=ne->size;
rt=true;
}
else if (description.isNewer(cur->second->description)){
int oldKb=cur->second->size/1024;
CacheEntry::Ptr ne=std::make_shared<CacheEntry>(d,description,key.size());
cache[key]=ne;
int newKb=ne->size;
numKb+=(newKb-oldKb);
rt=true;
}
numEntries=cache.size();
return rt;
}
TileCache::Png TileCache::getTile(const TileCache::CacheDescription &description, const TileInfo &tile){
Synchronized l(lock);
String key=getKey(tile);
auto cur=cache.find(key);
if (cur == cache.end()){
return TileCache::Png();
}
if (description.equals(cur->second->description)){
cur->second->lastAccess=Timer::steadyNow();
return cur->second->data;
}
return TileCache::Png();
}

TileCache::TileCache(size_t max):maxMem(max){
std::thread([this](){
while (! this->stopAudit){
Timer::microSleep(1000000L);
this->cleanup();
}
}).detach();
}

0 comments on commit 934f03f

Please sign in to comment.