alaCarte Maps
Renderer for OpenStreetMap tiles
request_manager.cpp
Go to the documentation of this file.
1 
24 #include "server/http_request.hpp"
28 #include "server/job.hpp"
30 
31 
33 {
34 private:
35  boost::mutex runningMutex;
36  std::list<Job*> jobs;
37 
38 public:
39  bool start(Job* job, const shared_ptr<MetaIdentifier>& mid)
40  {
41  boost::mutex::scoped_lock lock(runningMutex);
42  for (auto j : jobs) {
43  if (j->getIdentifier() == mid)
44  return false;
45  }
46 
47  jobs.push_back(job);
48  return true;
49  }
50 
52  bool start(Job* job, const shared_ptr<TileIdentifier>& ti, const shared_ptr<HttpRequest>& r)
53  {
54  boost::mutex::scoped_lock lock(runningMutex);
55  for (auto j : jobs) {
56  if (j->getIdentifier()->contains(ti)) {
57  j->addRequest(r, ti);
58  return false;
59  }
60  }
61 
62  jobs.push_back(job);
63  job->addRequest(r, ti);
64  return true;
65  }
66 
67  void finished(Job* job)
68  {
69  boost::mutex::scoped_lock lock(runningMutex);
70  jobs.remove(job);
71  }
72 };
73 
83 RequestManager::RequestManager( const shared_ptr<Configuration>& config,
84  const shared_ptr<Geodata>& data,
85  const shared_ptr<Renderer>& renderer,
86  const shared_ptr<Cache>& cache,
87  const shared_ptr<StylesheetManager>& ssm )
88  : config(config)
89  , data(data)
90  , renderer(renderer)
91  , cache(cache)
92  , ssm(ssm)
94  , running(new RunningQueue())
95 {
96  int threads = config->get<int>(opt::server::num_threads);
98  for (int i = 0; i < threads; ++i) {
99  auto worker = boost::make_shared<boost::thread>(
100  boost::bind(&boost::asio::io_service::run, &jobPool)
101  );
102  workers.push_back(worker);
103  factories.push(boost::make_shared<RenderCanvasFactory>());
104  }
105 
106  // start prerender timing
107  prerender_start = std::chrono::system_clock::now();
108 }
109 
115  stop();
116  LOG_SEV(request_log, debug) << "RequestManager destructed";
117 }
118 
124 {
125  jobPool.stop();
126  for (auto worker : workers) {
127  worker->join();
128  }
129  workers.clear();
130 }
131 
132 
138 void RequestManager::enqueue(const shared_ptr<HttpRequest>& r)
139 {
140  boost::mutex::scoped_lock userLock(userRJMutex);
141  if (userRequests.size() >= config->get<int>(opt::server::max_queue_size)) {
143  return;
144  }
145  userRequests.push(r);
146  userLock.unlock();
147 
148  jobPool.post( boost::bind(&RequestManager::processNextRequest, shared_from_this()) );
149 }
150 
151 
157 void RequestManager::enqueue(const shared_ptr<MetaIdentifier>& ti)
158 {
159  preRJMutex.lock();
160  preRenderRequests.push(ti);
161  preRJMutex.unlock();
162 
163  jobPool.post( boost::bind(&RequestManager::processNextRequest, shared_from_this()) );
164 }
165 
170 {
171  if (!nextUserRequest())
172  if (!nextPreRenderRequest())
173  LOG_SEV(request_log, error) << "Trying to run a job, but there is none.";
174 }
175 
181 {
182  boost::mutex::scoped_lock userLock(userRJMutex);
183  if (userRequests.empty())
184  return false;
185 
186  shared_ptr<HttpRequest> req = userRequests.front();
187  userRequests.pop();
188  userLock.unlock();
189 
190  shared_ptr<TileIdentifier> ti;
191  try
192  {
193  ti = TileIdentifier::Create(req->getURL(), this->ssm, config);
194  }
195  catch (excp::MalformedURLException &e)
196  {
197  LOG_SEV(request_log, info) << "MalformedURLException: "
198  << e.what() << " Url: " << req->getURL();
199 
200  req->answer(HttpRequest::Reply::forbidden);
201  }
203  {
204  LOG_SEV(request_log, info) << "UnknownImageFormatException: "
205  << e.what() << " Url: " << req->getURL();
206 
208  }
209 
210  // identifier could not be parsed
211  if (!ti)
212  return true;
213 
214  shared_ptr<MetaIdentifier> mid = MetaIdentifier::Create(ti);
215 
216  factoriesMutex.lock();
217  shared_ptr<RenderCanvasFactory> factory = factories.front();
218  factories.pop();
219  factoriesMutex.unlock();
220 
221  shared_ptr<RenderCanvas> canvas = factory->getCanvas(ti->getImageFormat());
222 
223  Job job(mid, config, shared_from_this(), canvas);
224 
225  // check if tiles are already in progress
226  if (running->start(&job, ti, req))
227  {
228  job.process();
229 
230  running->finished(&job);
231 
232  job.deliver();
233  }
234 
235  factoriesMutex.lock();
236  factories.push(factory);
237  factoriesMutex.unlock();
238 
239  return true;
240 }
241 
243 {
244  boost::mutex::scoped_lock preLock(preRJMutex);
245  if (preRenderRequests.empty())
246  return false;
247 
248  shared_ptr<MetaIdentifier> mid = preRenderRequests.front();
249  preRenderRequests.pop();
251  preLock.unlock();
252 
253  factoriesMutex.lock();
254  shared_ptr<RenderCanvasFactory> factory = factories.front();
255  factories.pop();
256  factoriesMutex.unlock();
257 
258  shared_ptr<RenderCanvas> canvas = factory->getCanvas(mid->getImageFormat());
259 
260  Job job(mid, config, shared_from_this(), canvas);
261 
262  // check if tiles are already in progress
263  if (running->start(&job, mid))
264  {
265  job.process();
266 
267  running->finished(&job);
268 
269  job.deliver();
270  }
271 
272  factoriesMutex.lock();
273  factories.push(factory);
274  factoriesMutex.unlock();
275 
276  if (!job.isEmpty() && mid->getZoom() < config->get<int>(opt::server::prerender_level)) {
277  std::vector<shared_ptr<MetaIdentifier>> children;
278  mid->getSubIdentifiers(children);
279  for (auto& c : children)
280  enqueue(c);
281  }
282 
283  preLock.lock();
285  preLock.unlock();
286 
287  if (currentPrerenderingThreads == 0 && preRenderRequests.size() == 0) {
288  prerender_stop = std::chrono::system_clock::now();
289  int elapsed_seconds = std::chrono::duration_cast<std::chrono::seconds>
291  LOG_SEV(request_log, info) << "Prerendering finished in "
292  << std::setfill('0') << std::setw(2) << elapsed_seconds / 60 << ":" << elapsed_seconds % 60;
293  }
294 
295  return true;
296 }
297 
303 shared_ptr<Geodata> RequestManager::getGeodata() const
304 {
305  return data;
306 }
307 
308 
314 shared_ptr<StylesheetManager> RequestManager::getStylesheetManager() const
315 {
316  return ssm;
317 }
318 
319 
325 shared_ptr<Cache> RequestManager::getCache() const
326 {
327  return cache;
328 }
329 
330 
336 shared_ptr<Renderer> RequestManager::getRenderer() const
337 {
338  return renderer;
339 }
340 
shared_ptr< Geodata > data
void addRequest(const shared_ptr< HttpRequest > &req, const shared_ptr< TileIdentifier > &id)
Definition: job.hpp:51
Thrown if an unknown image format is requested.
Definition: exceptions.hpp:83
TESTABLE shared_ptr< StylesheetManager > getStylesheetManager() const
Returns the StylesheetManager.
std::vector< shared_ptr< boost::thread > > workers
virtual const char * what() const
Definition: exceptions.hpp:62
void deliver()
Definition: job.cpp:205
bool nextUserRequest()
Selects the next Job and runs it process Method.
boost::mutex factoriesMutex
static shared_ptr< MetaIdentifier > Create(const shared_ptr< TileIdentifier > &origin)
This file is part of alaCarte.
void stop()
stops all jobs
void processNextRequest()
Selects the next Job and runs it process Method.
std::queue< shared_ptr< HttpRequest > > userRequests
TESTABLE void enqueue(const shared_ptr< HttpRequest > &r)
Enqueues the HttpRequest.
This file is part of alaCarte.
std::queue< shared_ptr< RenderCanvasFactory > > factories
std::chrono::system_clock::time_point prerender_stop
RequestManager(const shared_ptr< Configuration > &config, const shared_ptr< Geodata > &data, const shared_ptr< Renderer > &renderer, const shared_ptr< Cache > &cache, const shared_ptr< StylesheetManager > &ssm)
Constructs a new RequestManager with the given parameters.
boost::mutex preRJMutex
bool start(Job *job, const shared_ptr< TileIdentifier > &ti, const shared_ptr< HttpRequest > &r)
Abstract Class which computes Tiles by a given TileIdentifier.
Definition: job.hpp:41
#define LOG_SEV(log, lvl)
Definition: settings.hpp:78
shared_ptr< Cache > cache
bool start(Job *job, const shared_ptr< MetaIdentifier > &mid)
TESTABLE shared_ptr< Geodata > getGeodata() const
Returns the Geodata.
shared_ptr< Configuration > config
std::queue< shared_ptr< MetaIdentifier > > preRenderRequests
static const char * max_queue_size
Maximum size for the queue (type: int)
shared_ptr< Renderer > renderer
boost::asio::io_service::work preventStop
TESTABLE shared_ptr< Renderer > getRenderer() const
Returns the Renderer.
TESTABLE shared_ptr< Cache > getCache() const
Returns the Cache.
boost::asio::io_service jobPool
std::chrono::system_clock::time_point prerender_start
void process()
Computes a all tiles contained in the MetaIdentifier.
Definition: job.cpp:156
static shared_ptr< TileIdentifier > Create(const string &url, shared_ptr< StylesheetManager > StylesheetManager, const shared_ptr< Configuration > &config)
Constructs a new TileIdentifier with the given url.
shared_ptr< StylesheetManager > ssm
Thrown if URL is not in SlippyMap-URL-Format.
Definition: exceptions.hpp:81
static const char * num_threads
Option to get number of worker threads (type: int)
~RequestManager()
Stops the io_service, joins all Threads and destructs the RequestManager.
static const char * prerender_level
Option to get the timeout for request-processing (type: int)
scoped_ptr< RunningQueue > running
unsigned int currentPrerenderingThreads
boost::mutex userRJMutex
bool isEmpty()
Definition: job.hpp:55