3d7b84a598
The datasource cache was taking an exclusive lock on the simple mutex used to protect the singleton's data pointer. This works okay when everyone always calls it non-recursively, but when the recursive flag is true then it will always deadlock when called on any directory with subdirectories. Additionally, many methods which accessed private data members of the cache were not protected by any locks. Since the call pattern of registering datasources is strictly tree-shaped then it's a good candidate for a recursive mutex. This has a slightly higher overhead than a simple mutex, so rather than change the singleton's mutex to be recursive, I've added a new instance mutex to the datasource cache. Also, added a very basic test which reproduces the problem and shows that it's fixed with this patch.
71 lines
2.4 KiB
C++
71 lines
2.4 KiB
C++
/*****************************************************************************
|
|
*
|
|
* This file is part of Mapnik (c++ mapping toolkit)
|
|
*
|
|
* Copyright (C) 2015 Artem Pavlenko
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#ifndef MAPNIK_DATASOURCE_CACHE_HPP
|
|
#define MAPNIK_DATASOURCE_CACHE_HPP
|
|
|
|
// mapnik
|
|
#include <mapnik/config.hpp>
|
|
#include <mapnik/util/singleton.hpp>
|
|
#include <mapnik/util/noncopyable.hpp>
|
|
|
|
// stl
|
|
#include <map>
|
|
#include <set>
|
|
#include <vector>
|
|
#include <memory>
|
|
#include <mutex>
|
|
|
|
namespace mapnik {
|
|
|
|
class datasource;
|
|
class parameters;
|
|
class PluginInfo;
|
|
|
|
class MAPNIK_DECL datasource_cache
|
|
: public singleton<datasource_cache, CreateStatic>,
|
|
private util::noncopyable
|
|
{
|
|
friend class CreateStatic<datasource_cache>;
|
|
public:
|
|
std::vector<std::string> plugin_names();
|
|
std::string plugin_directories();
|
|
bool register_datasources(std::string const& path, bool recurse = false);
|
|
bool register_datasource(std::string const& path);
|
|
std::shared_ptr<datasource> create(parameters const& params);
|
|
private:
|
|
datasource_cache();
|
|
~datasource_cache();
|
|
std::map<std::string,std::shared_ptr<PluginInfo> > plugins_;
|
|
std::set<std::string> plugin_directories_;
|
|
// the singleton has a mutex protecting the instance pointer,
|
|
// but the instance also needs its own mutex to protect the
|
|
// plugins_ and plugin_directories_ members which are potentially
|
|
// modified recusrively by register_datasources(path, true);
|
|
std::recursive_mutex instance_mutex_;
|
|
};
|
|
|
|
extern template class MAPNIK_DECL singleton<datasource_cache, CreateStatic>;
|
|
|
|
}
|
|
|
|
#endif // MAPNIK_DATASOURCE_CACHE_HPP
|