alaCarte Maps
Renderer for OpenStreetMap tiles
cache.cpp
Go to the documentation of this file.
1 
23 #include "server/cache.hpp"
24 
27 #include "server/tile.hpp"
28 #include "server/stylesheet.hpp"
29 
30 #include "utils/exceptions.hpp"
31 
32 #include <boost/unordered_map.hpp>
33 #include <fstream>
34 
35 
36 Cache::Cache(const shared_ptr<Configuration>& config)
37  : Config(config)
38  , AllCaches()
39  , RecentlyUsedList()
40  , DefaultTile()
41 {
42 }
43 
44 void Cache::readFile(const Tile::ImageType& image, const boost::filesystem::path& filename) {
45  std::ifstream file;
46  file.open(filename.string(), std::ios::in | std::ios::binary);
47  file.seekg(0, std::ios::end);
48  std::streampos length(file.tellg());
49  if (length == std::streampos(-1) || !file.is_open()) {
50  BOOST_THROW_EXCEPTION(excp::FileNotFoundException() << excp::InfoFileName(filename.string()));
51  } else if (length) {
52  file.seekg(0, std::ios::beg);
53 
54  image->resize(static_cast<std::size_t>(length));
55  image->assign(std::istreambuf_iterator<char>(file),
56  std::istreambuf_iterator<char>());
57  }
58 }
59 
60 void Cache::writeFile(shared_ptr<Tile> tile, const boost::filesystem::path& filename) {
61  boost::filesystem::create_directories(filename.parent_path());
62  std::ofstream out(filename.string(), std::ios::out | std::ios::binary);
63  if(out.is_open())
64  {
65  Tile::ImageType png = tile->getImage();
66  if (png==0) {
67  out.close();
68  boost::filesystem::remove(filename);
69  BOOST_THROW_EXCEPTION(excp::InputFormatException());
70  } else {
71  auto size = png->size();
72  out.write((const char*) png->data(), size);
73  }
74  } else {
75  // e.g. Disk full
76  BOOST_THROW_EXCEPTION(excp::FileNotFoundException() << excp::InfoFileName(filename.string()));
77  }
78 }
79 
80 const boost::filesystem::path Cache::getTilePath(const shared_ptr<TileIdentifier>& ti) {
81  std::stringstream path;
82  path << Config->get<string>(opt::server::cache_path) << "/";
83  path << ti->getStylesheetPath() << "/";
84  path << ti->getZoom() << "/";
85  path << ti->getX() << "/";
86  path << ti->getY();
87  path << "." << ti->getImageFormatString();
88  boost::filesystem::path file(path.str());
89  return file;
90 }
91 
97 shared_ptr<Tile> Cache::getTile(const shared_ptr<TileIdentifier>& ti)
98 {
99  // TODO: Finer Synchronization
100  GlobalCacheLock.lock();
101  shared_ptr<CacheOfOneStylesheet> cache;
102  const string& stylesheet = ti->getStylesheetPath();
103  auto cacheIt = AllCaches.find(stylesheet);
104  if (cacheIt != AllCaches.end()) {
105  // Found cache for Stylesheet.
106  cache = cacheIt->second;
107  } else {
108  // Creating a new cache for stylesheet.
109  cache = boost::make_shared<CacheOfOneStylesheet>();
110  AllCaches[stylesheet] = cache;
111  boost::filesystem::path dir(Config->get<string>(opt::server::cache_path) + "/" + ti->getStylesheetPath());
112  boost::filesystem::create_directories(dir);
113  LOG_SEV(cache_log, debug) << "Stylesheetcache " << stylesheet << " created.";
114  }
115  // Get tile from map
116  shared_ptr<Tile> tile;
117  auto tileIt = cache->find(*ti);
118  if (tileIt != cache->end()) {
119  // Cache hit
120  tile = tileIt->second.first;
121  RecentlyUsedList.erase(tileIt->second.second);
122  RecentlyUsedList.push_front(tileIt->second.first);
123  tileIt->second.second = RecentlyUsedList.begin();
124  } else {
125  // Cache miss
126  tile = boost::make_shared<Tile>(ti);
127  if (ti->getZoom() <= Config->get<int>(opt::server::cache_keep_tile)) {
128  // Try to load prerendered image data from file.
129  boost::filesystem::path path = getTilePath(ti);
130  Tile::ImageType image = boost::make_shared<Tile::ImageType::element_type>();
131  try {
132  readFile(image, path);
133  tile->setImage(image);
134  } catch (excp::FileNotFoundException) {
135  LOG_SEV(cache_log, debug) << "readFile: Not found: " << path.string();
136  }
137  }
138  RecentlyUsedList.push_front(tile);
139  cache->insert(std::make_pair(*ti, CacheElement(tile, RecentlyUsedList.begin())));
140  }
141  while (RecentlyUsedList.size() > Config->get<int>(opt::server::cache_size)) {
142  shared_ptr<Tile> tileToDelete = RecentlyUsedList.back();
143  // Evict a Tile when cache is full.
144  if (tileToDelete->getIdentifier()->getZoom() <= Config->get<int>(opt::server::cache_keep_tile)) {
145  // Evict to hard drive.
146  shared_ptr<TileIdentifier> tiToDelete = tileToDelete->getIdentifier();
147  boost::filesystem::path path = getTilePath(tiToDelete);
148  try {
149  writeFile(tileToDelete, path);
150  } catch (excp::FileNotFoundException) {
151  LOG_SEV(cache_log, debug) << "WriteFile: Could not open file " << path.string();
152  // Disk is full
153  } catch (excp::InputFormatException) {
154  LOG_SEV(cache_log, debug) << "WriteFile: Image not yet rendered " << *tile->getIdentifier();
155  RecentlyUsedList.push_front(tileToDelete);
156  cacheIt = AllCaches.find(tileToDelete->getIdentifier()->getStylesheetPath());
157  if (cacheIt != AllCaches.end()) {
158  cacheIt->second->erase(*tileToDelete->getIdentifier());
159  cacheIt->second->insert(std::make_pair(*tiToDelete, CacheElement(tileToDelete, RecentlyUsedList.begin())));
160  }
161  RecentlyUsedList.pop_back();
162  break;
163  }
164  }
165  // Delete tile
166  LOG_SEV(cache_log, debug) << "Deleting least recently used Tile." << *tileToDelete->getIdentifier();
167  cacheIt = AllCaches.find(tileToDelete->getIdentifier()->getStylesheetPath());
168  if (cacheIt != AllCaches.end()) {
169  cacheIt->second->erase(*tileToDelete->getIdentifier());
170  }
171  RecentlyUsedList.pop_back();
172  }
173  GlobalCacheLock.unlock();
174  return tile;
175 }
176 
182 shared_ptr<Tile> Cache::getDefaultTile() {
183  if (!DefaultTile) {
184  string path = Config->get<string>(opt::server::path_to_default_tile);
185  shared_ptr<TileIdentifier> ti = boost::make_shared<TileIdentifier>(-1, -1, -1, "/", TileIdentifier::Format::PNG);
186  DefaultTile = boost::make_shared<Tile>(ti);
187  // Load default tile
188  Tile::ImageType image = boost::make_shared<Tile::ImageType::element_type>();
189  try {
190  readFile(image, path);
191  DefaultTile->setImage(image);
192  } catch (excp::FileNotFoundException) {
193 
194  }
195  }
196  return DefaultTile;
197 }
198 
204 void Cache::deleteTiles(const string path)
205 {
206  try {
207  boost::filesystem::path dir(Config->get<string>(opt::server::cache_path) + path);
208  boost::system::error_code ec;
209  boost::filesystem::remove_all(dir, ec);
210  if (ec.value() == 39) {
211  LOG_SEV(cache_log, warning) << "could not delete all tiles in folder.";
212  }
213  AllCaches.erase(path);
214  } catch (std::out_of_range) {
215  LOG_SEV(cache_log, warning) << "trying to delete Tiles of non existant Stylesheet.";
216  }
217 }
218 
void readFile(const Tile::ImageType &image, const boost::filesystem::path &filename)
Definition: cache.cpp:44
Cache(const shared_ptr< Configuration > &config)
This file is part of alaCarte.
Definition: cache.cpp:36
static const char * cache_size
Option to get the cache size (type: int)
Thrown if input was not in the right format.
Definition: exceptions.hpp:77
const boost::filesystem::path getTilePath(const shared_ptr< TileIdentifier > &ti)
Definition: cache.cpp:80
shared_ptr< Tile > DefaultTile
Definition: cache.hpp:74
static const char * cache_keep_tile
Option to get the zoomlevel until tiles are kept on harddrive (type: int)
TileList RecentlyUsedList
Definition: cache.hpp:73
#define LOG_SEV(log, lvl)
Definition: settings.hpp:78
TESTABLE shared_ptr< Tile > getDefaultTile()
Get the default tile used for error and such.
Definition: cache.cpp:182
Thrown if a file was not found.
Definition: exceptions.hpp:73
TESTABLE void deleteTiles(const string path)
Deletes all cached Tiles of the Stylesheet with the given path.
Definition: cache.cpp:204
CacheContainer AllCaches
Definition: cache.hpp:72
static const char * path_to_default_tile
Path to the default tile (type: string)
static const char * config
Option to get the configuration filename (type: string)
shared_ptr< Configuration > Config
Definition: cache.hpp:70
shared_ptr< std::vector< uint8_t > > ImageType
Definition: tile.hpp:33
static const char * cache_path
Option to get the cache path (type: string)
std::pair< shared_ptr< Tile >, TileList::iterator > CacheElement
An element stored in the cache.
Definition: cache.hpp:50
boost::mutex GlobalCacheLock
Definition: cache.hpp:71
boost::error_info< struct TagFileName, string > InfoFileName
Use this to inform about a file name.
Definition: exceptions.hpp:43
void writeFile(shared_ptr< Tile > tile, const boost::filesystem::path &filename)
Definition: cache.cpp:60
TESTABLE shared_ptr< Tile > getTile(const shared_ptr< TileIdentifier > &tl)
Gets a Tile where the image data can be stored.
Definition: cache.cpp:97