Commit 7c0e1396 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[2097] overall documentation update

parent f4833d50
......@@ -65,11 +65,8 @@ RdataSet::create(util::MemorySegment& mem_sgmt, RdataEncoder& encoder,
if (sig_rrset && sig_rrset->getRdataCount() == 0) {
isc_throw(BadValue, "Empty SIG RRset");
}
if (rrset && sig_rrset) {
if (rrset->getClass() != sig_rrset->getClass()) {
isc_throw(BadValue,
"RR class doesn't match between RRset and RRSIG");
}
if (rrset && sig_rrset && rrset->getClass() != sig_rrset->getClass()) {
isc_throw(BadValue, "RR class doesn't match between RRset and RRSIG");
}
// Check assumptions on the number of RDATAs
......@@ -135,7 +132,7 @@ RdataSet::destroy(util::MemorySegment& mem_sgmt, RRClass rrclass,
rdataset->getRdataCount(),
rdataset->getSigRdataCount()).getSize();
const size_t ext_rrsig_count_len =
rdataset->sig_rdata_count_ >= MANY_RRSIG_COUNT ? sizeof(uint16_t) : 0;
rdataset->sig_rdata_count_ == MANY_RRSIG_COUNT ? sizeof(uint16_t) : 0;
rdataset->~RdataSet();
mem_sgmt.deallocate(rdataset,
sizeof(RdataSet) + ext_rrsig_count_len + data_len);
......
......@@ -41,12 +41,155 @@ public:
Exception(file, line, what) {}
};
/// \brief Memory-efficient representation of RRset data with RRSIGs.
///
/// This class provides memory-efficient and lightweight interface to various
/// attributes of an RRset, which may or may not be signed with RRSIGs.
///
/// This class is primarily intended to be used in the in-memory data source
/// implementation, and is not supposed to be used by general applications.
/// The major design goals is to keep required memory footprint for the given
/// amount of data as small as possible, while providing reasonably efficient
/// interface to examine the data, focusing on zone lookup and DNS message
/// rendering.
///
/// It encodes a specific set of RRset and (when signed) its RRSIGs, excluding
/// the owner name and the RR class. The owner name is supposed to be
/// maintained by the application outside this class (the intended place to
/// store this information is a \c DomainTree node, although this
/// implementation does not rely on that intent). The RR class must be the
/// same in a single zone, and it's simply a waste if we have it with each
/// RRset. The RR class information is therefore expected to be maintained
/// outside this class.
///
/// This class imposes some limitations on the number of RDATAs of the RRset
/// and RRSIG: a (non RRSIG) RRset containing more than 8191 (2^13 - 1)
/// or an RRSIG containing more than 65535 (2^16 - 1) RDATAs cannot be
/// maintained in this class. The former restriction comes from the
/// following observation: any RR in wire format in a DNS message must at
/// least contain 10 bytes of data (for RR type, class, TTL and RDATA length),
/// and since a valid DNS message must not be larger than 65535 bytes,
/// no valid DNS response can contain more than 6554 RRs. So, in practice,
/// it should be reasonable even if we reject very large RRsets that would
/// not fit in a DNS message. For the same reason we restrict the number of
/// RRSIGs, although due to internal implementation details the limitation
/// is more relaxed for RRSIGs.
///
/// \note (This is pure implementation details) By limiting the number of
/// RDATAs so it will fit in a 13-bit integer, we can use 3 more bits in a
/// 2-byte integer for other purposes. We use this additional field to
/// represent the number of RRSIGs up to 6, while using the value of 7 to mean
/// there are more than 6 RRSIGs. In the vast majority of real world
/// deployment, an RRset should normally have only a few RRSIGs, and 6 should
/// normally be more than sufficient. So we can cover most practical cases
/// regarding the number of records with this 2-byte field.
///
/// A set of objects of this class (which would be \c RdataSets of various
/// types of the same owner name) will often be maintained in a single linked
/// list. The class has a member variable to make the link.
///
/// This class is designed so an instance can be stored in a shared
/// memory region. So it only contains straightforward data (e.g., it
/// doesn't hold a pointer to an object of some base class that
/// contains virtual methods), and the pointer member (see the
/// previous paragraph) is represented as an offset pointer. For the
/// same reason this class should never have virtual methods (and as a
/// result, should never be inherited in practice). When this class
/// is extended these properties must be preserved.
///
/// The \c RdataSet class itself only contains a subset of attributes that
/// it is conceptually expected to contain. The rest of the attributes
/// are encoded in a consecutive memory region immediately following the main
/// \c RdataSet object. The memory layout would be as follows:
/// \verbatim
/// RdataSet object
/// (optional) uint16_t: number of RRSIGs, if it's larger than 6 (see above)
/// encoded RDATA (generated by RdataEncoder) \endverbatim
///
/// This is shown here only for reference purposes. The application must not
/// assume any particular format of data in this region directly; it must
/// get access to it via public interfaces provided in the main \c RdataSet
/// class.
class RdataSet {
public:
/// \brief Allocate and construct \c RdataSet
///
/// This static method allocates memory for a new \c RdataSet
/// object for the set of an RRset and (if it's supposed to be signed)
/// RRSIG from the given memory segment, constructs the object, and
/// returns a pointer to it.
///
/// Normally the (non RRSIG) RRset is given (\c rrset is not NULL) while
/// its RRSIG (\c sig_rrset) may or may not be provided. But it's also
/// expected that in some rare (mostly broken) cases there can be an RRSIG
/// RR in a zone without having the covered RRset in the zone. To handle
/// such cases, this class allows to only hold RRSIG, in which case
/// \c rrset can be NULL. At least \c rrset or \c sig_rrset must be
/// non NULL, however. Also, if non NULL, the RRset must not be empty,
/// that is, it must contain at least one RDATA.
///
/// The RR type of \c rrset must not be RRSIG; the RR type of \c sig_rrset
/// must be RRSIG.
///
/// When both \c rrset and \c sig_rrset are provided (both are non
/// NULL), the latter must validly cover the former: the RR class
/// must be identical; the type covered field of any RDATA of \c
/// sig_rrset must be identical to the RR type of \c rrset. The owner
/// name of these RRsets must also be identical, but this implementation
/// doesn't require it because \c RdataSet itself does not rely on the
/// owner name, and it should be pretty likely that this condition is met
/// in the context where this class is used (and, name comparison is
/// relatively expensive, and if we end up comparing them twice the
/// overhead can be non negligible).
///
/// If any of the above conditions isn't met, an isc::BadValue exception
/// will be thrown; basically, there should be a bug in the caller if this
/// happens.
///
/// Due to implementation limitations, this class cannot contain more than
/// 8191 RDATAs for the non RRISG RRset; also, it cannot contain more than
/// 65535 RRSIGs. If the given RRset(s) fail to meet this condition,
/// an \c RdataSetError exception will be thrown.
///
/// \throw isc::BadValue Given RRset(s) are invalid (see the description)
/// \throw RdataSetError Number of RDATAs exceed the limits
/// \throw std::bad_alloc Memory allocation fails.
///
/// \param mem_sgmt A \c MemorySegment from which memory for the new
/// \c RdataSet is allocated.
/// \param encoder The RDATA encoder to encode \c rrset and \c sig_rrset
/// with the \c RdataSet to be created.
/// \param rrset A (non RRSIG) RRset from which the \c RdataSet is to be
/// created. Can be NULL if sig_rrset is not.
/// \param sig_rrset An RRSIG RRset from which the \c RdataSet is to be
/// created. Can be NULL if rrset is not.
///
/// \return A pointer to the created \c RdataSet.
static RdataSet* create(util::MemorySegment& mem_sgmt,
RdataEncoder& encoder,
dns::ConstRRsetPtr rrset,
dns::ConstRRsetPtr sig_rrset);
/// \brief Destruct and deallocate \c RdataSet
///
/// Note that this method needs to know the expected RR class of the
/// \c RdataSet. This is because the destruction may depend on the
/// internal data encoding that only \c RdataEncoder and \c RdataReader
/// know, and they need to know the corresponding RR class and type to
/// identify the internal data representation. Since \c RdataSet itself
/// does not hold the class information, the caller needs to provide it.
/// Obviously, this RR class must be identical to the RR class of \c rrset
/// (when given) or of \c sig_rrset (when \c rrset isn't given) at the
/// \c create() time.
///
/// \throw none
///
/// \param mem_sgmt The \c MemorySegment that allocated memory for
/// \c node.
/// \param rrclass The RR class of the \c RdataSet to be destroyed.
/// \param rdataset A non NULL pointer to a valid \c RdataSet object
/// that was originally created by the \c create() method (the behavior
/// is undefined if this condition isn't met).
static void destroy(util::MemorySegment& mem_sgmt, dns::RRClass rrclass,
RdataSet* rdataset);
......@@ -56,19 +199,38 @@ public:
// Note: the size and order of the members are carefully chosen to
// maximize efficiency. Don't change them unless there's strong reason
// for that and the consequences are considered.
// For convenience (and since this class is mostly intended to be an
// internal definition for the in-memory data source implementation),
// we allow the application to get access to some members directly.
// Some others require some conversion to use in a meaningful way,
// for which we force the application to use accessor methods in order
// to prevent misuse.
RdataSetPtr next; ///< Pointer to the next \c RdataSet (when linked)
const dns::RRType type; ///< The RR type of the \c RdataSet
RdataSetPtr next;
const dns::RRType type;
private:
const uint16_t sig_rdata_count_ : 3;
const uint16_t rdata_count_ : 13;
const uint32_t ttl_; ///< TTL of the RdataSet, net byte order
const uint16_t sig_rdata_count_ : 3; // # of RRSIGs, up to 6 (7 means many)
const uint16_t rdata_count_ : 13; // # of RDATAs, up to 8191
const uint32_t ttl_; // TTL of the RdataSet, net byte order
// Max number of normal RDATAs that can be stored in \c RdataSet.
// It's 2^13 - 1 = 8191.
static const size_t MAX_RDATA_COUNT = (1 << 13) - 1;
// Max number of RRSIGs that can be stored in \c RdataSet.
// It's 2^16 - 1 = 65535.
static const size_t MAX_RRSIG_COUNT = (1 << 16) - 1;
// Indicate the \c RdataSet contains many RRSIGs that require an additional
// field for the real number of RRSIGs. It's 2^3 - 1 = 7.
static const size_t MANY_RRSIG_COUNT = (1 << 3) - 1;
public:
/// \brief Return the number of RDATAs stored in the \c RdataSet.
size_t getRdataCount() const { return (rdata_count_); }
/// \brief Return the number of RRSIG RDATAs stored in the \c RdataSet.
size_t getSigRdataCount() const {
if (sig_rdata_count_ < MANY_RRSIG_COUNT) {
return (sig_rdata_count_);
......@@ -76,21 +238,40 @@ public:
return (*getExtSIGCountBuf());
}
}
/// \brief Return a pointer to the TTL data of the \c RdataSet.
///
/// The returned pointer points to a memory region that is valid at least
/// for 32 bits, storing the TTL of the \c RdataSet in the network byte
/// order. It returns opaque data to make it clear that unless the wire
/// format data is necessary (e.g., when rendering it in a DNS message),
/// it should be converted to, e.g., an \c RRTTL object explicitly.
///
/// \throw none
const void* getTTLData() const { return (&ttl_); }
void* getDataBuf() {
return (getDataBuf<void, RdataSet>(this));
}
/// \brief Accessor to the memory region for encoded RDATAs.
///
/// The only valid usage of the returned pointer is to pass it to
/// the constructor of \c RdataReader.
///
/// \throw none
const void* getDataBuf() const {
return (getDataBuf<const void, const RdataSet>(this));
}
private:
uint16_t* getExtSIGCountBuf() {
return (reinterpret_cast<uint16_t*>(this + 1));
}
const uint16_t* getExtSIGCountBuf() const {
return (reinterpret_cast<const uint16_t*>(this + 1));
/// \brief Accessor to the memory region for encoded RDATAs, mutable
/// version.
///
/// This version is only used within the class implementation, so it's
/// defined as private.
void* getDataBuf() {
return (getDataBuf<void, RdataSet>(this));
}
// Implementation of getDataBuf(). Templated to unify the mutable and
// immutable versions.
template <typename RetType, typename ThisType>
static RetType* getDataBuf(ThisType* rdataset) {
if (rdataset->sig_rdata_count_ < MANY_RRSIG_COUNT) {
......@@ -100,8 +281,33 @@ private:
}
}
/// \brief Accessor to the memory region for the RRSIG count field for
/// a large number of RRSIGs.
///
/// These are used only internally and defined as private.
const uint16_t* getExtSIGCountBuf() const {
return (reinterpret_cast<const uint16_t*>(this + 1));
}
uint16_t* getExtSIGCountBuf() {
return (reinterpret_cast<uint16_t*>(this + 1));
}
/// \brief The constructor.
///
/// An object of this class is always expected to be created by the
/// allocator (\c create()), so the constructor is hidden as private.
///
/// It never throws an exception.
RdataSet(dns::RRType type, size_t rdata_count, size_t sig_rdata_count,
dns::RRTTL ttl);
/// \brief The destructor.
///
/// An object of this class is always expected to be destroyed explicitly
/// by \c destroy(), so the destructor is hidden as private.
///
/// This currently does nothing, but is explicitly defined to clarify
/// it's intentionally defined as private.
~RdataSet() {}
};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment