zone_table_segment_mapped.cc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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/memory/zone_table_segment_mapped.h>
  15. #include <memory>
  16. using namespace isc::data;
  17. using namespace isc::dns;
  18. using namespace isc::util;
  19. namespace isc {
  20. namespace datasrc {
  21. namespace memory {
  22. ZoneTableSegmentMapped::ZoneTableSegmentMapped(const RRClass& rrclass) :
  23. ZoneTableSegment(rrclass),
  24. rrclass_(rrclass),
  25. header_(NULL)
  26. {
  27. }
  28. void
  29. ZoneTableSegmentMapped::reset(MemorySegmentOpenMode mode,
  30. isc::data::ConstElementPtr params)
  31. {
  32. if (mem_sgmt_) {
  33. if (isWritable()) {
  34. // If there is a previously opened segment, and it was
  35. // opened in read-write mode, update its checksum.
  36. mem_sgmt_->shrinkToFit();
  37. const MemorySegment::NamedAddressResult result =
  38. mem_sgmt_->getNamedAddress("zone_table_checksum");
  39. assert(result.first);
  40. assert(result.second);
  41. uint32_t* checksum = static_cast<uint32_t*>(result.second);
  42. // First, clear the checksum so that getCheckSum() returns
  43. // a consistent value.
  44. *checksum = 0;
  45. const uint32_t new_checksum = mem_sgmt_->getCheckSum();
  46. // Now, update it into place.
  47. *checksum = new_checksum;
  48. }
  49. // Close the segment here in case the code further below
  50. // doesn't complete successfully.
  51. header_ = NULL;
  52. mem_sgmt_.reset();
  53. }
  54. if (!params || params->getType() != Element::map) {
  55. isc_throw(isc::InvalidParameter,
  56. "Configuration does not contain a map");
  57. }
  58. if (!params->contains("mapped-file")) {
  59. isc_throw(isc::InvalidParameter,
  60. "Configuration does not contain a \"mapped-file\" key");
  61. }
  62. ConstElementPtr mapped_file = params->get("mapped-file");
  63. if ((!mapped_file) || (mapped_file->getType() != Element::string)) {
  64. isc_throw(isc::InvalidParameter,
  65. "Value of \"mapped-file\" is not a string");
  66. }
  67. const std::string filename = mapped_file->stringValue();
  68. // In case there is a checksum mismatch, we throw. We want the
  69. // segment to be automatically destroyed then.
  70. std::auto_ptr<MemorySegmentMapped> segment;
  71. switch (mode) {
  72. case CREATE: {
  73. segment.reset(new MemorySegmentMapped
  74. (filename,
  75. MemorySegmentMapped::CREATE_ONLY));
  76. // There must be no previously saved checksum.
  77. MemorySegment::NamedAddressResult result =
  78. segment->getNamedAddress("zone_table_checksum");
  79. if (result.first) {
  80. isc_throw(isc::Unexpected,
  81. "There is already a saved checksum in a mapped segment "
  82. "opened in create mode.");
  83. }
  84. // Allocate space for a checksum (which is saved during close).
  85. void* checksum = segment->allocate(sizeof(uint32_t));
  86. *static_cast<uint32_t*>(checksum) = 0;
  87. segment->setNamedAddress("zone_table_checksum", checksum);
  88. // There must be no previously saved ZoneTableHeader.
  89. result = segment->getNamedAddress("zone_table_header");
  90. if (result.first) {
  91. isc_throw(isc::Unexpected,
  92. "There is already a saved ZoneTableHeader in a "
  93. "mapped segment opened in create mode.");
  94. }
  95. void* ptr = segment->allocate(sizeof(ZoneTableHeader));
  96. ZoneTableHeader* new_header = new(ptr)
  97. ZoneTableHeader(ZoneTable::create(*segment, rrclass_));
  98. segment->setNamedAddress("zone_table_header", new_header);
  99. header_ = new_header;
  100. break;
  101. }
  102. case READ_WRITE: {
  103. segment.reset(new MemorySegmentMapped
  104. (filename, MemorySegmentMapped::OPEN_OR_CREATE));
  105. // If there is a previously saved checksum, verify that it is
  106. // consistent. Otherwise, allocate space for a checksum (which
  107. // is saved during close).
  108. MemorySegment::NamedAddressResult result =
  109. segment->getNamedAddress("zone_table_checksum");
  110. if (result.first) {
  111. // The segment was already shrunk when it was last
  112. // closed. Check that its checksum is consistent.
  113. assert(result.second);
  114. uint32_t* checksum = static_cast<uint32_t*>(result.second);
  115. const uint32_t saved_checksum = *checksum;
  116. // First, clear the checksum so that getCheckSum() returns
  117. // a consistent value.
  118. *checksum = 0;
  119. const uint32_t new_checksum = segment->getCheckSum();
  120. if (saved_checksum != new_checksum) {
  121. isc_throw(isc::Unexpected,
  122. "Saved checksum doesn't match mapped segment data");
  123. }
  124. } else {
  125. void* checksum = segment->allocate(sizeof(uint32_t));
  126. *static_cast<uint32_t*>(checksum) = 0;
  127. segment->setNamedAddress("zone_table_checksum", checksum);
  128. }
  129. // If there is a previously saved ZoneTableHeader, use
  130. // it. Otherwise, allocate a new header.
  131. result = segment->getNamedAddress("zone_table_header");
  132. if (result.first) {
  133. assert(result.second);
  134. header_ = static_cast<ZoneTableHeader*>(result.second);
  135. } else {
  136. void* ptr = segment->allocate(sizeof(ZoneTableHeader));
  137. ZoneTableHeader* new_header = new(ptr)
  138. ZoneTableHeader(ZoneTable::create(*segment, rrclass_));
  139. segment->setNamedAddress("zone_table_header", new_header);
  140. header_ = new_header;
  141. }
  142. break;
  143. }
  144. case READ_ONLY: {
  145. segment.reset(new MemorySegmentMapped(filename));
  146. // There must be a previously saved checksum.
  147. MemorySegment::NamedAddressResult result =
  148. segment->getNamedAddress("zone_table_checksum");
  149. if (!result.first) {
  150. isc_throw(isc::Unexpected,
  151. "There is no previously saved checksum in a "
  152. "mapped segment opened in read-only mode.");
  153. }
  154. // We can't verify the checksum here as we can't set the
  155. // checksum to 0 for checksum calculation in a read-only
  156. // segment. So we continue without verifying the checksum.
  157. // There must be a previously saved ZoneTableHeader.
  158. result = segment->getNamedAddress("zone_table_header");
  159. if (result.first) {
  160. assert(result.second);
  161. header_ = static_cast<ZoneTableHeader*>(result.second);
  162. } else {
  163. isc_throw(isc::Unexpected,
  164. "There is no previously saved ZoneTableHeader in a "
  165. "mapped segment opened in read-only mode.");
  166. }
  167. }
  168. }
  169. current_mode_ = mode;
  170. mem_sgmt_.reset(segment.release());
  171. }
  172. // After more methods' definitions are added here, it would be a good
  173. // idea to move getHeader() and getMemorySegment() definitions to the
  174. // header file.
  175. ZoneTableHeader&
  176. ZoneTableSegmentMapped::getHeader() {
  177. if (!mem_sgmt_) {
  178. isc_throw(isc::Unexpected,
  179. "getHeader() called without calling reset() first");
  180. }
  181. return (*header_);
  182. }
  183. const ZoneTableHeader&
  184. ZoneTableSegmentMapped::getHeader() const {
  185. if (!mem_sgmt_) {
  186. isc_throw(isc::Unexpected,
  187. "getHeader() called without calling reset() first");
  188. }
  189. return (*header_);
  190. }
  191. MemorySegment&
  192. ZoneTableSegmentMapped::getMemorySegment() {
  193. if (!mem_sgmt_) {
  194. isc_throw(isc::Unexpected,
  195. "getMemorySegment() called without calling reset() first");
  196. }
  197. return (*mem_sgmt_);
  198. }
  199. bool
  200. ZoneTableSegmentMapped::isWritable() const {
  201. if (!mem_sgmt_) {
  202. // If reset() was never performed for this segment, or if the
  203. // most recent reset() had failed, then the segment is not
  204. // writable.
  205. return (false);
  206. }
  207. return ((current_mode_ == CREATE) || (current_mode_ == READ_WRITE));
  208. }
  209. } // namespace memory
  210. } // namespace datasrc
  211. } // namespace isc