cache_config.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <datasrc/cache_config.h>
  15. #include <datasrc/client.h>
  16. #include <datasrc/memory/load_action.h>
  17. #include <datasrc/memory/zone_data_loader.h>
  18. #include <util/memory_segment.h>
  19. #include <dns/name.h>
  20. #include <dns/rrclass.h>
  21. #include <cc/data.h>
  22. #include <exceptions/exceptions.h>
  23. #include <boost/bind.hpp>
  24. #include <cassert>
  25. #include <map>
  26. #include <string>
  27. using namespace isc::data;
  28. namespace isc {
  29. namespace datasrc {
  30. namespace internal {
  31. namespace {
  32. bool
  33. getEnabledFromConf(const Element& conf) {
  34. return (conf.contains("cache-enable") &&
  35. conf.get("cache-enable")->boolValue());
  36. }
  37. std::string
  38. getSegmentTypeFromConf(const Element& conf) {
  39. // If cache-type is not explicitly configured, use the default type.
  40. // (Ideally we should retrieve the default from the spec).
  41. if (!conf.contains("cache-type")) {
  42. return ("local");
  43. }
  44. return (conf.get("cache-type")->stringValue());
  45. }
  46. }
  47. CacheConfig::CacheConfig(const std::string& datasrc_type,
  48. const DataSourceClient* datasrc_client,
  49. const Element& datasrc_conf,
  50. bool allowed) :
  51. enabled_(allowed && getEnabledFromConf(datasrc_conf)),
  52. segment_type_(getSegmentTypeFromConf(datasrc_conf)),
  53. datasrc_client_(datasrc_client)
  54. {
  55. ConstElementPtr params = datasrc_conf.get("params");
  56. if (!params) {
  57. params.reset(new NullElement());
  58. }
  59. if (datasrc_type == "MasterFiles") {
  60. if (datasrc_client_) {
  61. isc_throw(InvalidParameter,
  62. "data source client is given for MasterFiles");
  63. }
  64. if (!enabled_) {
  65. isc_throw(CacheConfigError,
  66. "The cache must be enabled for the MasterFiles type");
  67. }
  68. typedef std::map<std::string, ConstElementPtr> ZoneToFile;
  69. const ZoneToFile& zone_to_file = params->mapValue();
  70. ZoneToFile::const_iterator const it_end = zone_to_file.end();
  71. for (ZoneToFile::const_iterator it = zone_to_file.begin();
  72. it != it_end;
  73. ++it)
  74. {
  75. zone_config_[dns::Name(it->first)] = it->second->stringValue();
  76. }
  77. } else {
  78. if (!datasrc_client_) {
  79. isc_throw(InvalidParameter,
  80. "data source client is missing for data source type: "
  81. << datasrc_type);
  82. }
  83. if (!enabled_) {
  84. return;
  85. }
  86. if (!datasrc_conf.contains("cache-zones")) {
  87. isc_throw(NotImplemented, "Auto-detection of zones "
  88. "to cache is not yet implemented, supply "
  89. "cache-zones parameter");
  90. // TODO: Auto-detect list of all zones in the
  91. // data source.
  92. }
  93. const ConstElementPtr zones = datasrc_conf.get("cache-zones");
  94. if (zones->empty()) {
  95. return;
  96. }
  97. for (size_t i = 0; i < zones->size(); ++i) {
  98. const dns::Name zone_name(zones->get(i)->stringValue());
  99. if (!zone_config_.insert(Zones::value_type(zone_name,
  100. "")).second) {
  101. isc_throw(CacheConfigError, "Duplicate cache zone: " <<
  102. zone_name);
  103. }
  104. }
  105. }
  106. }
  107. namespace {
  108. // We would like to use boost::bind for this. However, the loadZoneData takes
  109. // a reference, while we have a shared pointer to the iterator -- and we need
  110. // to keep it alive as long as the ZoneWriter is alive. Therefore we can't
  111. // really just dereference it and pass it, since it would get destroyed once
  112. // the getCachedZoneWriter would end. This class holds the shared pointer
  113. // alive, otherwise is mostly simple.
  114. //
  115. // It might be doable with nested boost::bind, but it would probably look
  116. // more awkward and complicated than this.
  117. class IteratorLoader {
  118. public:
  119. IteratorLoader(const dns::RRClass& rrclass, const dns::Name& name,
  120. const ZoneIteratorPtr& iterator) :
  121. rrclass_(rrclass),
  122. name_(name),
  123. iterator_(iterator)
  124. {}
  125. memory::ZoneData* operator()(util::MemorySegment& segment) {
  126. return (memory::loadZoneData(segment, rrclass_, name_, *iterator_));
  127. }
  128. private:
  129. const dns::RRClass rrclass_;
  130. const dns::Name name_;
  131. ZoneIteratorPtr iterator_;
  132. };
  133. // We can't use the loadZoneData function directly in boost::bind, since
  134. // it is overloaded and the compiler can't choose the correct version
  135. // reliably and fails. So we simply wrap it into an unique name.
  136. memory::ZoneData*
  137. loadZoneDataFromFile(util::MemorySegment& segment, const dns::RRClass& rrclass,
  138. const dns::Name& name, const std::string& filename)
  139. {
  140. return (memory::loadZoneData(segment, rrclass, name, filename));
  141. }
  142. } // unnamed namespace
  143. memory::LoadAction
  144. CacheConfig::getLoadAction(const dns::RRClass& rrclass,
  145. const dns::Name& zone_name) const
  146. {
  147. // First, check if the specified zone is configured to be cached.
  148. Zones::const_iterator found = zone_config_.find(zone_name);
  149. if (found == zone_config_.end()) {
  150. return (memory::LoadAction());
  151. }
  152. if (!found->second.empty()) {
  153. // This is "MasterFiles" data source.
  154. return (boost::bind(loadZoneDataFromFile, _1, rrclass, zone_name,
  155. found->second));
  156. }
  157. // Otherwise there must be a "source" data source (ensured by constructor)
  158. assert(datasrc_client_);
  159. // If the specified zone name does not exist in our client of the source,
  160. // NoSuchZone is thrown, which is exactly the result what we
  161. // want, so no need to handle it.
  162. ZoneIteratorPtr iterator(datasrc_client_->getIterator(zone_name));
  163. if (!iterator) {
  164. // This shouldn't happen for a compliant implementation of
  165. // DataSourceClient, but we'll protect ourselves from buggy
  166. // implementations.
  167. isc_throw(Unexpected, "getting LoadAction for " << zone_name
  168. << "/" << rrclass << " resulted in Null zone iterator");
  169. }
  170. // Wrap the iterator into the correct functor (which keeps it alive as
  171. // long as it is needed).
  172. return (IteratorLoader(rrclass, zone_name, iterator));
  173. }
  174. } // namespace internal
  175. } // namespace datasrc
  176. } // namespace isc