Branch data Line data Source code
1 : : // Copyright (C) 2010 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 : :
15 : : #ifndef __MEMORY_DATA_SOURCE_H
16 : : #define __MEMORY_DATA_SOURCE_H 1
17 : :
18 : : #include <string>
19 : :
20 : : #include <boost/noncopyable.hpp>
21 : :
22 : : #include <datasrc/zonetable.h>
23 : : #include <datasrc/client.h>
24 : :
25 : : #include <cc/data.h>
26 : :
27 : : namespace isc {
28 : : namespace dns {
29 : : class Name;
30 : : class RRsetList;
31 : : };
32 : :
33 : : namespace datasrc {
34 : :
35 : : /// A derived zone finder class intended to be used with the memory data source.
36 : : ///
37 : : /// Conceptually this "finder" maintains a local in-memory copy of all RRs
38 : : /// of a single zone from some kind of source (right now it's a textual
39 : : /// master file, but it could also be another data source with a database
40 : : /// backend). This is why the class has methods like \c load() or \c add().
41 : : ///
42 : : /// This class is non copyable.
43 : : class InMemoryZoneFinder : boost::noncopyable, public ZoneFinder {
44 : : ///
45 : : /// \name Constructors and Destructor.
46 : : public:
47 : : /// \brief Constructor from zone parameters.
48 : : ///
49 : : /// This constructor internally involves resource allocation, and if
50 : : /// it fails, a corresponding standard exception will be thrown.
51 : : /// It never throws an exception otherwise.
52 : : ///
53 : : /// \param rrclass The RR class of the zone.
54 : : /// \param origin The origin name of the zone.
55 : : InMemoryZoneFinder(const isc::dns::RRClass& rrclass,
56 : : const isc::dns::Name& origin);
57 : :
58 : : /// The destructor.
59 : : virtual ~InMemoryZoneFinder();
60 : : //@}
61 : :
62 : : /// \brief Returns the origin of the zone.
63 : : virtual isc::dns::Name getOrigin() const;
64 : :
65 : : /// \brief Returns the class of the zone.
66 : : virtual isc::dns::RRClass getClass() const;
67 : :
68 : : /// \brief Find an RRset in the datasource
69 : : virtual ZoneFinderContextPtr find(const isc::dns::Name& name,
70 : : const isc::dns::RRType& type,
71 : : const FindOptions options =
72 : : FIND_DEFAULT);
73 : :
74 : : /// \brief Version of find that returns all types at once
75 : : ///
76 : : /// It acts the same as find, just that when the correct node is found,
77 : : /// all the RRsets are filled into the target parameter instead of being
78 : : /// returned by the result.
79 : : virtual ZoneFinderContextPtr findAll(
80 : : const isc::dns::Name& name,
81 : : std::vector<isc::dns::ConstRRsetPtr>& target,
82 : : const FindOptions options = FIND_DEFAULT);
83 : :
84 : : /// Look for NSEC3 for proving (non)existence of given name.
85 : : ///
86 : : /// See documentation in \c Zone.
87 : : virtual FindNSEC3Result
88 : : findNSEC3(const isc::dns::Name& name, bool recursive);
89 : :
90 : : /// \brief Imelementation of the ZoneFinder::findPreviousName method
91 : : ///
92 : : /// This one throws NotImplemented exception, as InMemory doesn't
93 : : /// support DNSSEC currently.
94 : : virtual isc::dns::Name findPreviousName(const isc::dns::Name& query) const;
95 : :
96 : : /// \brief Inserts an rrset into the zone.
97 : : ///
98 : : /// It puts another RRset into the zone.
99 : : ///
100 : : /// In the current implementation, this method doesn't allow an existing
101 : : /// RRset to be updated or overridden. So the caller must make sure that
102 : : /// all RRs of the same type and name must be given in the form of a
103 : : /// single RRset. The current implementation will also require that
104 : : /// when an RRSIG is added the RRset to be covered has already been
105 : : /// added. These restrictions are probably too strict when this data
106 : : /// source accepts various forms of input, so they should be revisited
107 : : /// later.
108 : : ///
109 : : /// Except for NullRRset and OutOfZone, this method does not guarantee
110 : : /// strong exception safety (it is currently not needed, if it is needed
111 : : /// in future, it should be implemented).
112 : : ///
113 : : /// \throw NullRRset \c rrset is a NULL pointer.
114 : : /// \throw OutOfZone The owner name of \c rrset is outside of the
115 : : /// origin of the zone.
116 : : /// \throw AddError Other general errors.
117 : : /// \throw Others This method might throw standard allocation exceptions.
118 : : ///
119 : : /// \param rrset The set to add.
120 : : /// \return SUCCESS or EXIST (if an rrset for given name and type already
121 : : /// exists).
122 : : result::Result add(const isc::dns::ConstRRsetPtr& rrset);
123 : :
124 : : /// \brief RRset is NULL exception.
125 : : ///
126 : : /// This is thrown if the provided RRset parameter is NULL.
127 : 1 : struct NullRRset : public InvalidParameter {
128 : : NullRRset(const char* file, size_t line, const char* what) :
129 : 2 : InvalidParameter(file, line, what)
130 : : { }
131 : : };
132 : :
133 : : /// \brief General failure exception for \c add().
134 : : ///
135 : : /// This is thrown against general error cases in adding an RRset
136 : : /// to the zone.
137 : : ///
138 : : /// Note: this exception would cover cases for \c OutOfZone or
139 : : /// \c NullRRset. We'll need to clarify and unify the granularity
140 : : /// of exceptions eventually. For now, exceptions are added as
141 : : /// developers see the need for it.
142 : 26 : struct AddError : public InvalidParameter {
143 : 26 : AddError(const char* file, size_t line, const char* what) :
144 : 52 : InvalidParameter(file, line, what)
145 : 26 : { }
146 : : };
147 : :
148 : : /// Return the master file name of the zone
149 : : ///
150 : : /// This method returns the name of the zone's master file to be loaded.
151 : : /// The returned string will be an empty unless the zone finder has
152 : : /// successfully loaded a zone.
153 : : ///
154 : : /// This method should normally not throw an exception. But the creation
155 : : /// of the return string may involve a resource allocation, and if it
156 : : /// fails, the corresponding standard exception will be thrown.
157 : : ///
158 : : /// \return The name of the zone file loaded in the zone finder, or an empty
159 : : /// string if the zone hasn't loaded any file.
160 : : const std::string getFileName() const;
161 : :
162 : : /// \brief Load zone from masterfile.
163 : : ///
164 : : /// This loads data from masterfile specified by filename. It replaces
165 : : /// current content. The masterfile parsing ability is kind of limited,
166 : : /// see isc::dns::masterLoad.
167 : : ///
168 : : /// This throws isc::dns::MasterLoadError if there is problem with loading
169 : : /// (missing file, malformed, it contains different zone, etc - see
170 : : /// isc::dns::masterLoad for details).
171 : : ///
172 : : /// In case of internal problems, OutOfZone, NullRRset or AssertError could
173 : : /// be thrown, but they should not be expected. Exceptions caused by
174 : : /// allocation may be thrown as well.
175 : : ///
176 : : /// If anything is thrown, the previous content is preserved (so it can
177 : : /// be used to update the data, but if user makes a typo, the old one
178 : : /// is kept).
179 : : ///
180 : : /// \param filename The master file to load.
181 : : ///
182 : : /// \todo We may need to split it to some kind of build and commit/abort.
183 : : /// This will probably be needed when a better implementation of
184 : : /// configuration reloading is written.
185 : : void load(const std::string& filename);
186 : :
187 : : /// \brief Load zone from another data source.
188 : : ///
189 : : /// This is similar to the other version, but zone's RRsets are provided
190 : : /// by an iterator of another data source. On successful load, the
191 : : /// internal filename will be cleared.
192 : : ///
193 : : /// This implementation assumes the iterator produces combined RRsets,
194 : : /// that is, there should exactly one RRset for the same owner name and
195 : : /// RR type. This means the caller is expected to create the iterator
196 : : /// with \c separate_rrs being \c false. This implementation also assumes
197 : : /// RRsets of different names are not mixed; so if the iterator produces
198 : : /// an RRset of a different name than that of the previous RRset, that
199 : : /// previous name must never appear in the subsequent sequence of RRsets.
200 : : /// Note that the iterator API does not ensure this. If the underlying
201 : : /// implementation does not follow it, load() will fail. Note, however,
202 : : /// that this whole interface is tentative. in-memory zone loading will
203 : : /// have to be revisited fundamentally, and at that point this restriction
204 : : /// probably won't matter.
205 : : void load(ZoneIterator& iterator);
206 : :
207 : : /// Exchanges the content of \c this zone finder with that of the given
208 : : /// \c zone_finder.
209 : : ///
210 : : /// This method never throws an exception.
211 : : ///
212 : : /// \param zone_finder Another \c InMemoryZone object which is to
213 : : /// be swapped with \c this zone finder.
214 : : void swap(InMemoryZoneFinder& zone_finder);
215 : :
216 : : private:
217 : : /// \name Hidden private data
218 : : //@{
219 : : struct InMemoryZoneFinderImpl;
220 : : InMemoryZoneFinderImpl* impl_;
221 : : //@}
222 : : // The friend here is for InMemoryClient::getIterator. The iterator
223 : : // needs to access the data inside the zone, so the InMemoryClient
224 : : // extracts the pointer to data and puts it into the iterator.
225 : : // The access is read only.
226 : : friend class InMemoryClient;
227 : :
228 : : /// \brief In-memory version of finder context.
229 : : ///
230 : : /// The implementation (and any specialized interface) is completely local
231 : : /// to the InMemoryZoneFinder class, so it's defined as private
232 : : class Context;
233 : : };
234 : :
235 : : /// \brief A data source client that holds all necessary data in memory.
236 : : ///
237 : : /// The \c InMemoryClient class provides an access to a conceptual data
238 : : /// source that maintains all necessary data in a memory image, thereby
239 : : /// allowing much faster lookups. The in memory data is a copy of some
240 : : /// real physical source - in the current implementation a list of zones
241 : : /// are populated as a result of \c addZone() calls; zone data is given
242 : : /// in a standard master file (but there's a plan to use database backends
243 : : /// as a source of the in memory data).
244 : : ///
245 : : /// Although every data source client is assumed to be of the same RR class,
246 : : /// the \c InMemoryClient class does not enforce the assumption through
247 : : /// its interface.
248 : : /// For example, the \c addZone() method does not check if the new zone is of
249 : : /// the same RR class as that of the others already in memory.
250 : : /// It is caller's responsibility to ensure this assumption.
251 : : ///
252 : : /// <b>Notes to developer:</b>
253 : : ///
254 : : /// The addZone() method takes a (Boost) shared pointer because it would be
255 : : /// inconvenient to require the caller to maintain the ownership of zones,
256 : : /// while it wouldn't be safe to delete unnecessary zones inside the dedicated
257 : : /// backend.
258 : : ///
259 : : /// The findZone() method takes a domain name and returns the best matching
260 : : /// \c InMemoryZoneFinder in the form of (Boost) shared pointer, so that it can
261 : : /// provide the general interface for all data sources.
262 : : class InMemoryClient : public DataSourceClient {
263 : : public:
264 : : ///
265 : : /// \name Constructors and Destructor.
266 : : ///
267 : : //@{
268 : :
269 : : /// Default constructor.
270 : : ///
271 : : /// This constructor internally involves resource allocation, and if
272 : : /// it fails, a corresponding standard exception will be thrown.
273 : : /// It never throws an exception otherwise.
274 : : InMemoryClient();
275 : :
276 : : /// The destructor.
277 : : ~InMemoryClient();
278 : : //@}
279 : :
280 : : /// Return the number of zones stored in the client.
281 : : ///
282 : : /// This method never throws an exception.
283 : : ///
284 : : /// \return The number of zones stored in the client.
285 : : unsigned int getZoneCount() const;
286 : :
287 : : /// Add a zone (in the form of \c ZoneFinder) to the \c InMemoryClient.
288 : : ///
289 : : /// \c zone_finder must not be associated with a NULL pointer; otherwise
290 : : /// an exception of class \c InvalidParameter will be thrown.
291 : : /// If internal resource allocation fails, a corresponding standard
292 : : /// exception will be thrown.
293 : : /// This method never throws an exception otherwise.
294 : : ///
295 : : /// \param zone_finder A \c ZoneFinder object to be added.
296 : : /// \return \c result::SUCCESS If the zone_finder is successfully
297 : : /// added to the client.
298 : : /// \return \c result::EXIST The memory data source already
299 : : /// stores a zone that has the same origin.
300 : : result::Result addZone(ZoneFinderPtr zone_finder);
301 : :
302 : : /// Returns a \c ZoneFinder for a zone_finder that best matches the given
303 : : /// name.
304 : : ///
305 : : /// This derived version of the method never throws an exception.
306 : : /// For other details see \c DataSourceClient::findZone().
307 : : virtual FindResult findZone(const isc::dns::Name& name) const;
308 : :
309 : : /// \brief Implementation of the getIterator method
310 : : virtual ZoneIteratorPtr getIterator(const isc::dns::Name& name,
311 : : bool separate_rrs = false) const;
312 : :
313 : : /// In-memory data source is read-only, so this derived method will
314 : : /// result in a NotImplemented exception.
315 : : ///
316 : : /// \note We plan to use a database-based data source as a backend
317 : : /// persistent storage for an in-memory data source. When it's
318 : : /// implemented we may also want to allow the user of the in-memory client
319 : : /// to update via its updater (this may or may not be a good idea and
320 : : /// is subject to further discussions).
321 : : virtual ZoneUpdaterPtr getUpdater(const isc::dns::Name& name,
322 : : bool replace, bool journaling = false)
323 : : const;
324 : :
325 : : virtual std::pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
326 : : getJournalReader(const isc::dns::Name& zone, uint32_t begin_serial,
327 : : uint32_t end_serial) const;
328 : :
329 : : private:
330 : : // TODO: Do we still need the PImpl if nobody should manipulate this class
331 : : // directly any more (it should be handled through DataSourceClient)?
332 : : class InMemoryClientImpl;
333 : : InMemoryClientImpl* impl_;
334 : : };
335 : :
336 : : /// \brief Creates an instance of the Memory datasource client
337 : : ///
338 : : /// Currently the configuration passed here must be a MapElement, formed as
339 : : /// follows:
340 : : /// \code
341 : : /// { "type": string ("memory"),
342 : : /// "class": string ("IN"/"CH"/etc),
343 : : /// "zones": list
344 : : /// }
345 : : /// Zones list is a list of maps:
346 : : /// { "origin": string,
347 : : /// "file": string
348 : : /// }
349 : : /// \endcode
350 : : /// (i.e. the configuration that was used prior to the datasource refactor)
351 : : ///
352 : : /// This configuration setup is currently under discussion and will change in
353 : : /// the near future.
354 : : ///
355 : : /// \param config The configuration for the datasource instance
356 : : /// \param error This string will be set to an error message if an error occurs
357 : : /// during initialization
358 : : /// \return An instance of the memory datasource client, or NULL if there was
359 : : /// an error
360 : : extern "C" DataSourceClient* createInstance(isc::data::ConstElementPtr config,
361 : : std::string& error);
362 : :
363 : : /// \brief Destroy the instance created by createInstance()
364 : : extern "C" void destroyInstance(DataSourceClient* instance);
365 : :
366 : :
367 : : }
368 : : }
369 : : #endif // __DATA_SOURCE_MEMORY_H
370 : : // Local Variables:
371 : : // mode: c++
372 : : // End:
|